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

StackOverflow https://stackoverflow.com/questions/162042

  •  03-07-2019
  •  | 
  •  

質問

それに直面しましょう。シングルトンパターンは非常に物議を醸すトピックであり、の大群プログラマフェンスの両側。シングルトンは栄光に満ちたグローバル変数に過ぎないと感じている人もいれば、パターンに誓って絶えず使用している人もいます。 Singleton Controversy を中心にしたくないしかし、私の質問の。 誰でも綱引きを持って戦い、誰が勝つかを見ることができます。私が言おうとしているのは、正解が1つしかないとは思わず、意図的に党派論争を引き起こそうとはしていないということです。質問をするとき、シングルトンの代替物に単に興味があります:

GOFシングルトンパターンの具体的な代替手段はありますか

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

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

編集:これは、「シングルトンを正しく使用する方法」に関する別の投稿にはなりたくない。繰り返しますが、私はそれを避ける方法を探しています。楽しみのために、大丈夫?私はあなたの最高の映画の予告編の声で純粋にアカデミックな質問をしていると思います、「シングルトンのない並行宇宙では、私たちは何ができますか?」

役に立ちましたか?

解決

" 嫌いなパターン&quotのAlex Miller ;以下を引用します:

"シングルトンが答えのように思える場合、次のことが賢明であることがよくあります。

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

他のヒント

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

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

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

依存関係を非表示にすると、カップリングの量がわからなくなる傾向があります。

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

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つだけであることを保証できます。

管理するのは複雑ですが、このブログ投稿"すべてのシングルトンはどこに行ったのですか?、それはとても自然に思えます。余談ですが、単体テストの分離に役立ちます。

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

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にバンドルされます。

これが役立つことを願っています。間違いを指摘してください。

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

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

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

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

シングルトンパターンが存在するのは、一連のサービスを提供するために単一のオブジェクトが必要な場合があるためです

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

したがって、古典的なシングルトンパターンの代わりに、サービスコンテナでサービスの「like」パターンを使用することをお勧めします。静的フィールドでシングルトンを使用する代わりに、それへの参照を取得します必要なサービスのタイプをリクエストするメソッドを介して。

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

単一のグローバルではなく

*pseudocode* singletonType.Instance

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

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

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

Monostate(Robert C. Martinのアジャイルソフトウェア開発で説明)は、シングルトンの代替です。このパターンでは、クラスのデータはすべて静的ですが、ゲッター/セッターは非静的です。

例:

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
        }
    }
}

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

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

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

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

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

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

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

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

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

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

シングルトンをポリシングするのに最適な場所は、クラス設計レベルです。この段階で、クラス間の相互作用をマップし、アプリケーションの存続期間中にこのクラスのインスタンスが1つだけ存在することが絶対に必要かどうかを確認できるはずです。

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

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

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

強烈なオブジェクト指向環境(Javaなど)でプログラミングされていないので、私は議論の複雑さについて完全には理解していません。しかし、私はPHP 4にシングルトンを実装しました。これは、自動的に初期化される「ブラックボックス」データベースハンドラーを作成する方法として実行しました。

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

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

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

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top