GOFシングルトンパターンの実行可能な代替案はありますか?


91

それに直面しよう。Singletonパターンは、非常に論争の大群プログラマーとトピックの両方フェンスの脇。シングルトンは栄光のグローバル変数に過ぎないと感じている人や、パターンで誓い、それを絶え間なく使用している人もいます。ただし、シングルトン論争が私の質問の中心にあるのは望ましくありません。 誰もが綱引きを持って戦い、私が気にかけているすべてのことで誰が勝つかを確認できます。私が言おうとしているのは、正解が1つあるとは思わないことであり、意図的に炎上党派の口論をしようとしているのではありません。私が質問するとき、私は単にシングルトンの選択肢に興味があります:

GOFシングルトンパターンに代わるものはありますか?

たとえば、過去にシングルトンパターンを何度も使用したことがあるのですが、1つまたは複数の変数の状態/値を保存することに単に関心があります。ただし、変数の状態/値は、シングルトンパターンを使用する代わりに、静的変数を使用してクラスの各インスタンス化間で保持できます。

他にどんなアイデアがありますか?

編集: 「シングルトンを正しく使用する方法」に関する別の投稿にしたくありません。繰り返しますが、それを回避する方法を探しています。楽しいですか?私はあなたの映画の予告編の声で純粋に学術的な質問をしていると思います。「シングルトンが存在しないパラレルユニバースでは、何ができるでしょうか?」


何?良くも悪くもありませんが、どうすれば交換できますか?それが良いと言うすべての人にとって、参加しないでください。悪いと言う人はみな、それなしで私がどう生きられるかを見せて証明してください。私には反論のように聞こえます。
S.Lott、2008年

@CodingWithoutComents:投稿全体を読みました。それが「シングルトンでいいなら返事をしない」という感覚を得た方法です。
S.Lott、2008年

2
まあ、それがそれが出会った方法であるならば、私は謝罪します。私は分極を避けるために重要なステップを踏んだと思いました。シングルトンの愛好家と嫌悪者の両方が、プログラマーとして私たち全員が選択肢を持っていることでそれを取り除くことができるような方法で質問をしたと思いました-彼らは正しい唯一の方法ではないということです
CodingWithoutComments

シングルトンを使用する場合、それらを回避する方法については貢献できません。二極化するような音。
S.Lott、2008年

9
私は毎日シングルトンを使用していますが、それで物事を行うにはもっと良い方法があるのではないかと考えるのをやめますか?デザインパターンは14年間しか使用されていません。私はそれらを聖書の真実と見なしますか?既成概念にとらわれずに考えることをやめますか 私たちはCSの規律を前進させようと試みませんか?
CodingWithoutComments 2008年

回答:


76

嫌いなパターン」のアレックス・ミラーは次のように引用しています。

「シングルトンが答えのように思えるとき、私はそれがしばしば賢明であることに気づきます:

  1. シングルトンのインターフェースとデフォルト実装を作成する
  2. システムの「上部」にデフォルト実装の単一インスタンスを構築します。これは、Spring構成、コード、またはシステムに応じてさまざまな方法で定義されます。
  3. 単一のインスタンスを、それを必要とする各コンポーネントに渡します(依存性注入)

2
これが5歳に近いことは知っていますが、これについて詳しく教えていただけますか?シングルトンを作成する正しい方法はインターフェースを使用することだと私は教えられたと思います。私がやっていることが「大丈夫」で、私に言われたほどひどくなかったかどうかに興味があります。
Pureferret 2013

97

シングルトンを回避する適切な方法を理解するには、シングルトンの問題点(および一般的なグローバル状態)を理解する必要があります。

シングルトンは依存関係を隠します。

なぜそれが重要なのですか?

ので、あなたが依存関係を非表示にした場合、あなたはカップリングの量のトラックを失う傾向にあります。

あなたはそれを主張するかもしれません

void purchaseLaptop(String creditCardNumber, int price){
  CreditCardProcessor.getInstance().debit(creditCardNumber, amount);
  Cart.getInstance().addLaptop();
}

より単純です

void purchaseLaptop(CreditCardProcessor creditCardProcessor, Cart cart, 
                    String creditCardNumber, int price){
  creditCardProcessor.debit(creditCardNumber, amount);
  cart.addLaptop();
}

ただし、少なくとも2番目のAPIは、メソッドのコラボレーターが何であるかを明確に示します。

したがって、シングルトンを回避する方法は、静的変数またはサービスロケーターを使用するのではなく、シングルトンクラスをインスタンスに変更することです。これらは、意味のあるスコープでインスタンス化され、それらを必要とするコンポーネントとメソッドに注入されます。IoCフレームワークを使用してこれを処理することも、手動で行うこともできますが、重要なことは、グローバル状態を取り除き、依存関係とコラボレーションを明示的にすることです。


+1問題の回避方法だけでなく、問題の根本について議論するため。
Phil

9
本格的な多層アプリケーションでは、2番目の方法で不要なコードが大量に作成されることがよくあります。中間層のコードを下位層に持ち越すロジックで汚染することにより、そうでなければそのレベルでは不要なオブジェクトを、不要な依存関係を作成していませんか?ナビゲーションスタックの階層4が、ファイルのアップロードなどのバックグラウンドアクションを開始するとします。ここで、完了時にユーザーに警告したいとしますが、それまでにユーザーは、開始ビューと共通の層1のみを共有するアプリケーションのまったく異なる部分にいる可能性があります。大量の不要なコード...
Hari Karam Singh

1
@RasmusFaberシングルトンパターンは依存関係を隠しません。依存関係の非表示は、パターンとは別の問題です。パターンがこの間違いを犯しやすいことは事実ですが、IoCパターンとシングルトンパターンを一緒に実行することは非常に可能です。たとえば、インスタンスの特別なライフサイクル管理を必要とするサードパーティのライブラリを作成できます。私のライブラリを使用するユーザーは、シングルトンのインスタンスをクラスに「渡す」必要があります。すべてのポイントカットから。
Martin Bliss

@HariKaramSinghこれを回避するには、サブスクライブ/パブリッシュパターンまたはシステム全体のイベントバス(シングルトンではなく、すべての関係者で共有する必要があります)を使用できます。
ビクターソロキン2013年

4
また、pub / subまたはオブザーバーパターンは、それらに大きく依存するフレームワークを介してデバッグをステップ実行しなければならなかった人が証明するのと同じように、「カップリングの追跡を失う」のと同じくらい悪い場合があります。少なくともシングルトンの場合、呼び出されるメソッド名は呼び出しコードと同じ場所にあります:)個人的には、これらの戦略はすべてその場所にあり、何も盲目的に実装することはできません。ずさんなコーダーはどんなパターンからもスパゲッティを作り出し、責任のあるコーダーはエレガントなコードを作成するためにイデオロギーの制限に過度に負担する必要はありません。
Hari Karam Singh

14

私が出会った最高のソリューションは、ファクトリパターンを使用してクラスのインスタンスを構築することです。パターンを使用すると、それを使用するオブジェクト間で共有されるクラスのインスタンスが1つだけであることを保証できます。

管理は複雑になると思いますが、このブログ記事「シングルトンはどこに行ったの?」、それはとても自然なようです。余談ですが、単体テストを分離するのに役立ちます。

要約すると、何をする必要がありますか?オブジェクトが別のオブジェクトに依存するときはいつでも、そのオブジェクトのインスタンスを受け取るのはそのコンストラクターのみです(クラスに新しいキーワードはありません)。

class NeedyClass {

    private ExSingletonClass exSingleton;

    public NeedyClass(ExSingletonClass exSingleton){
        this.exSingleton = exSingleton;
    }

    // Here goes some code that uses the exSingleton object
}

そして、工場。

class FactoryOfNeedy {

    private ExSingletonClass exSingleton;

    public FactoryOfNeedy() {
        this.exSingleton = new ExSingletonClass();
    }

    public NeedyClass buildNeedy() {
        return new NeedyClass(this.exSingleton);
    }
}

ファクトリをインスタンス化するのは1回だけなので、exSingletonのインスタンス化は1つになります。buildNeedyを呼び出すたびに、NeedyClassの新しいインスタンスがexSingletonにバンドルされます。

これがお役に立てば幸いです。間違いを指摘してください。


5
プライベートコンストラクタが必要になり、buildNeedyメソッドを静的メソッドとして定義した場合にのみ、ファクトリがインスタンス化されるようにします。
ジュリアングレニエ

16
ジュリアンは正解です。この修正には根本的な欠陥があります。つまり、インスタンス化できるのは1つのファクトリのみであると暗黙のうちに言っています。(ジュリアンが言ったように)1つのファクトリのみがインスタンス化されるようにするために必要な予防措置を講じると、結局はシングルトンになります!実際には、このアプローチは、シングルトンの上に不必要な抽象化レイヤーを追加するだけです。
ボブソマーズ

インスタンスを1つだけにする別の方法があります。工場をインスタンス化できるのは1回だけです。コンパイラでこれを強制する必要はありません。これはまた、ユニットテストに役立ちたい別のインスタンスを。
2011

これは、シングルトンで誤って解決される問題に対して私がこれまでに見た中で最高のソリューションです-すべてのメソッド呼び出しを混乱させることなく依存関係を追加します(したがって、インターフェースを再設計し、その依存関係をリファクタリングします)。「シングルトン」のインスタンスが1つだけであることは重要ではないが、デフォルトで全員が同じインスタンスを共有することが重要である私の状況では、わずかな変更が最適です(変更は、ファクトリを使用する代わりに、静的を使用することです)共通インスタンスを外部で設定し、構築中にそのインスタンスを使用するメソッド)。
meustrus

したがって、基本的にこのアプローチの利点は、潜在的にオブジェクトの束全体(シングルトンを使用しないことを選択している)ではなく、1つのオブジェクトインスタンス(ファクトリ)をシャッフルするだけでよいということです。
Hari Karam Singh

9

Springまたはその他のIoCコンテナは、その点でかなり良い仕事をします。クラスはアプリ自体の外部で作成および管理されるため、コンテナーは単純なクラスをシングルトンにして、必要な場所にそれらを注入できます。


前述のトピックに関するリンクはありますか?
CodingWithoutComments 2008年

これらのフレームワークはJavaに固有のようです-他の言語固有のオプションはありますか?または言語にとらわれない?
CodingWithoutComments 2008年

.NETの場合:Castle Windsor castleproject.org/container/index.html Microsoft Unity msdn.microsoft.com/en-us/library/cc468366.aspx Unityは実際には依存性注入フレームワークですが、このトピックではおそらく機能します。
エリックファンブラケル

1
なぜこれに対する投票が多すぎないのですか?IOCは、シングルトンを回避するのに最適なソリューションです。
Sandeep Jindal 2013年

@CodingWithoutComments PHPにSymfonyサービスコンテナがあることを知っています。ルビーの男は依存関係を注入する他の方法があります。興味のある言語はありますか?
Bevelopper

9

パターンを回避するために邪魔になる必要はありません。パターンの使用は、設計上の決定または自然な適合のいずれかです(これは、適切に配置されるだけです)。システムを設計するときは、パターンを使用するかしないかを選択できます。ただし、最終的に設計上の選択となるものを回避するために邪魔にならないでください。

シングルトンパターンは避けません。それが適切で私がそれを使用するか、それが適切でなく私がそれを使用しないかのいずれかです。それはそれと同じくらい簡単だと思います。

シングルトンの妥当性(またはその欠如)は状況によって異なります。これは、設計上の決定であり、その決定の結果を理解(および文書化)する必要があります。


私は同じことを言うつもりでしたが、それは彼の質問には完全には答えません:)
Swati

2
それが適切であるか、適切でない場合は、回答で話し合ってください。プリティープリーズ。
CodingWithoutComments 2008年

それは質問に答えます。シングルトンパターンの使用を避けるためのテクニックはありません。それを避けるために自分の道を行くわけではないので、どの開発者もそうすべきではないと思うからです。
Thomas Owens、

それが適切であるか適切でないかは、一般化できないと思います。これはすべてプロジェクト固有であり、問​​題のシステムの設計に大きく依存します。私はこのような決定に「経験則」を使用しません。
Thomas Owens、

うーん。なぜこれが否決されているのか分かりません。私は質問に答えました-シングルトンパターンの使用を回避するためのテクニックは何ですか?-私はパターンを回避するために自分の道を離れないので、私にはテクニックがないと言います。反対投票者は推論について詳しく説明できますか?
Thomas Owens、

5

モノステート(ロバートC.マーティンのアジャイルソフトウェア開発で説明)は、シングルトンの代替手段です。このパターンでは、クラスのデータはすべて静的ですが、getter / setterは非静的です。

例えば:

public class MonoStateExample
{
    private static int x;

    public int getX()
    {
        return x;
    }

    public void setX(int xVal)
    {
        x = xVal;
    }
}

public class MonoDriver
{
    public static void main(String args[])
    {
        MonoStateExample m1 = new MonoStateExample();
        m1.setX(10);

        MonoStateExample m2 = new MonoStateExample();
        if(m1.getX() == m2.getX())
        {
            //singleton behavior
        }
    }
}

モノステートはシングルトンと同様の動作をしますが、プログラマがシングルトンが使用されているという事実を必ずしも認識していない方法でそうします。


これはより多くの投票に値します。MonoStateの復習を求めて、Googleからここに来ました。
mahemoff 2013

@Markスレッドの安全性の観点から、このデザインをロックダウンするのは非常に難しいようです。MonoStateExampleの静的変数ごとにインスタンスロックを作成しますか、それともすべてのプロパティが利用する1つのロックを作成しますか?両方とも、シングルトンパターンで実行して簡単に解決できる深刻な影響があります。
Martin Bliss

この例はシングルトンパターンの代替ですが、シングルトンパターンの問題を解決しません。
Sandeep Jindal 2013年

4

シングルトンときの状況があるので、パターンが存在する単一のオブジェクトは、一連のサービスを提供するために必要とされます

これが当てはまる場合でも、インスタンスを表すグローバルな静的フィールド/プロパティを使用してシングルトンを作成するアプローチは依然として不適切であると考えています。静的フィールドとオブジェクトではなく、オブジェクトが提供するサービスの間でコード内に依存関係を作成するため、これは不適切です。

そのため、クラシックなシングルトンパターンの代わりに、サービスコンテナーでサービスの「いいね」パターンを使用することをお勧めします。静的フィールドを通じてシングルトンを使用する代わりに、必要なサービスのタイプを要求するメソッドを通じてそれに対する参照を取得します。

*pseudocode* currentContainer.GetServiceByObjectType(singletonType)
//Under the covers the object might be a singleton, but this is hidden to the consumer.

単一のグローバルの代わりに

*pseudocode* singletonType.Instance

このようにして、オブジェクトのタイプをシングルトンから別のものに変更したい場合、簡単にそれを行うことができます。また、追加の利点として、オブジェクトインスタンスの割り当てをすべてのメソッドに渡す必要がありません。

Inversion of Controlも参照してください。シングルトンを直接コンシューマーに公開することにより、オブジェクトによって提供されるオブジェクトサービスではなく、コンシューマーとオブジェクトインスタンスの間に依存関係を作成するという考え方です。

私の意見は、シングルトンパターンの使用を可能な限り非表示にすることです。なぜなら、常にそれを回避することは不可能であるか、望ましいとは限らないからです。


サービスコンテナーの例にはあまり従いません。リンクできるオンラインリソースはありますか?
CodingWithoutComments 2008年

「Castle Project-Windsor Container」castleproject.org/container/index.htmlをご覧ください。残念ながら、このトピックに関する抽象的な出版物を見つけることは非常に困難です。
Pop Catalin、

2

シングルトンを使用して単一のデータオブジェクトを表す場合は、代わりにデータオブジェクトをメソッドパラメータとして渡すことができます。

(ただし、これは最初からシングルトンを使用する間違った方法であると主張します)


1

問題が状態を維持したい場合は、MumbleManagerクラスが必要です。システムでの作業を始める前に、クライアントはMumbleManagerを作成します。Mumbleはシステムの名前です。それによって状態は保持されます。MumbleManagerに状態を保持するプロパティバッグが含まれる可能性があります。

このタイプのスタイルは、Cのように感じられ、オブジェクトのようには感じられません。システムを定義するオブジェクトはすべて、同じMumbleManagerへの参照を持っていることがわかります。


シングルトンを支持したり反対したりせずに、私はこのソリューションがアンチパターンであることを言わなければなりません。MumbleManagerは、単一の責任に違反する、あらゆる種類の異なる知識を含む「神クラス」になります。それは同様にすべてのアプリケーションのケアのためのシングルトンかもしれません。
Martin Bliss

0

プレーンオブジェクトとファクトリオブジェクトを使用します。ファクトリは、インスタンスとプレーンオブジェクトの詳細を、構成情報(たとえば、それを含む)と動作のみを使用してポリシングします。


1
多くの場合、ファクトリはシングルトンではありませんか?通常、このようにしてFactoryパターンが実装されています。
Thomas Owens、

0

実際、シンゲルトンを回避するためにゼロから設計する場合、静的変数を使用してシングルトンを使用しないようにする必要はありません。静的変数を使用する場合、シングルトンも作成しますが、唯一の違いは異なるオブジェクトインスタンスを作成することですが、内部的にはすべてシングルトンを使用しているかのように動作します。

シングルトンを使用している場合、またはシングルトンが現在使用されており、使用を避けようとしている場合の詳細な例を挙げられますか?これは、シングルトンがなくても状況をどのように処理できるかという、より洗練されたソリューションを見つけるのに役立ちます。

ところで、私は個人的にシングルトンに問題はなく、他の人がシングルトンに関して抱えている問題を理解できません。私は彼らについて悪いことは何も見ていません。つまり、それらを悪用していない場合です。すべての有用なテクニックは乱用される可能性があり、乱用された場合、否定的な結果につながります。一般的に誤用されている別のテクニックは、継承です。それでも、継承をひどく悪用しているからといって、継承が悪いことだと言う人は誰もいません。


0

個人的には、シングルトンのように動作するものを実装するより賢明な方法は、完全に静的なクラス(静的メンバー、静的メソッド、静的プロパティ)を使用することです。ほとんどの場合、この方法で実装します(ユーザーの観点から見た動作の違いは考えられません)


0

シングルトンをポリシングするのに最適な場所は、クラスのデザインレベルだと思います。この段階で、クラス間の相互作用を図にして、何かが絶対に、アプリケーションのどの時点でもこのクラスのインスタンスが1つだけ存在していることが絶対に必要かどうかを確認できるはずです。

その場合は、シングルトンです。コーディング中に便宜上シングルトンを投入する場合は、設計を再検討し、上記のシングルトンのコーディングを停止する必要があります:)

そして、はい、「警察」は私がここで言う「避ける」というよりも言葉です。シングルトンは回避すべきものではありません(gotoおよびグローバル変数が回避すべきものではないのと同じように)。代わりに、使用状況を監視し、それが効果的に実行するための最良の方法であることを確認する必要があります。


1
私はあなたが言っていることを完全に理解しています。そして私は完全に同意します。しかし、あなたの答えはまだ私の質問に明確に答えていません。これが「シングルトンを使用するのが適切なのはいつか」という別の質問にしたくありませんでした。私はシングルトンに代わる実行可能な代替策に興味を持っていました。
CodingWithoutComments 2008年

0

私はシングルトンをほとんど「メソッドコンテナー」として使用し、状態はまったくありません。これらのメソッドを多くのクラスと共有する必要があり、インスタンス化と初期化の負担を避けたい場合は、コンテキスト/セッションを作成し、そこですべてのクラスを初期化します。セッションを参照するすべてのものは、含まれる「シングルトン」にもアクセスできます。


0

非常にオブジェクト指向の環境(Javaなど)でプログラミングしていないので、私は議論の複雑さについて完全には理解していません。しかし、私はPHP 4にシングルトンを実装しました。これは、自動的に初期化される「ブラックボックス」データベースハンドラーを作成する方法として行いました。不完全で多少壊れたフレームワークで関数呼び出しを上下に渡す必要はありませんでした。

シングルトンパターンのリンクをいくつか読んだ後、まったく同じ方法で実装するかどうかは完全にはわかりません。本当に必要だったのは、共有ストレージを備えた複数のオブジェクト(実際のデータベースハンドルなど)であり、これが私の呼び出しのほとんどになりました。

ほとんどのパターンやアルゴリズムと同様に、「クールだからといって」シングルトンを使用するのは、The Wrong Thing To Doです。私はたまたまシングルトンのように見える本当に「ブラックボックス」の呼び出しを必要としていました。そして、それが問題に取り組む方法であるIMOです。パターンに注意するだけでなく、より広い範囲と、インスタンスが一意である必要があるレベルを確認してください。


-1

どういう意味ですか、それを回避するための私のテクニックは何ですか?

それを「回避する」には、シングルトンパターンが自然に適切である多くの状況が発生することを意味します。したがって、これらの状況を解消するためにいくつかの対策を講じる必要があります。

しかし、ありません。シングルトンパターンを回避する必要はありません。それは単に発生しません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.