web-dev-qa-db-ja.com

シングルトンの代替品

アプリケーションの構成情報を保持するクラスがあります。以前はシングルトンでした。いくつかのアーキテクチャのレビューの後、シングルトンを削除するように言われました。さまざまな構成を一度にテストできるため、単体テストでシングルトンを使用しないことの利点がいくつかわかりました。

シングルトンがなければ、インスタンスをコードのどこにでも渡す必要があります。とても面倒なので、シングルトンラッパーを作成しました。今、同じコードをPHPと.NETに移植しています。構成オブジェクトに使用できるより良いパターンがあるかどうか疑問に思っています。

113
John Mill

Google Testing blog には、(テスト可能なコードを作成するための)シングルトンの回避に関する一連のエントリがあります。たぶんこれはあなたを助けることができます:

最後の記事では、新規オブジェクトの作成をファクトリーに移動する方法を詳細に説明しているため、シングルトンの使用を避けることができます。必ず読む価値がある。

つまり、すべての新しいオペレーターを工場に移動します。ライフタイムが似ているすべてのオブジェクトを1つのファクトリにグループ化します。

127
FrankS

最良の方法は、代わりにFactoryパターンを使用することです。 (ファクトリーで)クラスの新しいインスタンスを構築するとき、単一のインスタンス(ファクトリークラスに格納する)への参照として、または関連する新しいオブジェクトへのデータ。

すべてのオブジェクトには、シングルトンに住んでいたデータが含まれます。全体的に大きな違いはないと思いますが、コードを読みやすくすることができます。

15
gbjbaanb

私はここで明白なことを述べているかもしれませんが、 SpringGuice などの依存関係注入フレームワークを使用できない理由はありますか? (Springは.NETでも利用できるようになりました)。

そうすれば、フレームワークは構成オブジェクトの単一のコピーを保持でき、Bean(サービス、DAOなど)がルックアップを心配する必要はありません。

これは私が通常とるアプローチです!

5
user7094

単一の構成オブジェクトに責任を蓄積しないでください理解するのが難しく、壊れやすい非常に大きなオブジェクトで終わるためです。

たとえば、特定のクラスに別のパラメーターが必要な場合は、Configurationオブジェクトを変更し、それを使用するすべてのクラスを再コンパイルします。これはやや問題があります。

コードをリファクタリングして、共通のグローバルで大きなConfigurationオブジェクトを回避してください。必要なパラメーターのみをクライアントクラスに渡します。

class Server {

    int port;

    Server(Configuration config) {
        this.port = config.getServerPort();
    } 

}

リファクタリングする必要があります:

 class Server {

    public Server(int port) {
       this.port = port;
    }
 }

依存性注入フレームワークはここで大いに役立ちますが、厳密には必要ありません。

4
dfa

Spring Framework を使用すると、通常のBeanを作成できます。デフォルトでは(または明示的に_scope="singleton"_を設定した場合)、Beanのインスタンスが1つだけ作成され、Beanが依存関係で使用されるたび、またはgetBean()経由で取得されるたびにそのインスタンスが返されます。

シングルトンパターンを結合せずに、単一インスタンスの利点を活用できます。

4
CoverosGene

別の方法は、オブジェクトに物事を要求する代わりに、必要なものを渡すことです。

4
koen

静的メソッドを使用して、シングルトンと同じ動作を実現できます。 Steve yeggeが this postで非常によく説明しています。

1
Youssef

コールバックインターフェイスとして構成する可能性を確認します。したがって、構成に依存するコードは次のようになります。

MyReuseCode.Configure(IConfiguration)

System-initコードは次のようになります。

Library.init(MyIConfigurationImpl)
0
Dewfy

依存関係注入フレームワークを使用して、構成オブジェクトを渡す手間を軽減できます。まともなものは ninject で、xmlではなくコードを使用する利点があります。

0
Colin Gravill

静的メソッドと静的フィールドのみを含むクラスは可能ですか?あなたの状況は正確にはわかりませんが、調べる価値があるかもしれません。

0
Thomas Owens

あまりきれいでもないかもしれませんが、変更したい情報ビットを、シングルトンを作成するメソッドに渡すことができます-を使用する代わりに

_public static Singleton getInstance() {
    if(singleton != null)
        createSingleton();
        return singleton;
    }
}
_

アプリケーションの起動時に(および単体テストのsetUp-Methodsで)createSingleton(Information info)を直接呼び出すことができます。

0
Roland Ewald

どのツール/フレームワークなどが使用されているかに依存します。依存関係注入/ IOCツールでは、di/iocコンテナーがクラスのインスタンスを1つだけ作成することで、必要なクラス(IConfigSettingsインターフェイスなど)にシングルトン動作を使用させることで、シングルトンのパフォーマンス/最適化を得ることができます。これはまだテストに置き換えることができます

別の方法として、ファクトリを使用してクラスを作成し、リクエストするたびに同じインスタンスを返すことができますが、テストのためにスタブ/モックバージョンを返すことができます

0
saret