実用的なシングルトン&依存性注入の質問
-
05-07-2019 - |
質問
たとえば、システムに1回だけ存在するPermissionManagerというクラスがあり、基本的にアプリケーションのさまざまなアクションのさまざまな権限を管理する機能を果たしているとします。これで、アプリケーションにクラスがあり、そのメソッドの1つで特定の許可を確認できる必要があります。このクラスのコンストラクタは現在公開されています。つまり、APIユーザーが使用します。
数週間前までは、クラスで次の擬似コードをどこかに呼び出すだけでした:
PermissionManager.getInstance().isReadPermissionEnabled(this)
しかし、私はシングルトンとこの種のカップリングを嫌う全員に気付いたので、シングルトンに対して読んだ議論は理にかなっているように見えるので、より良い解決策は何だろうと思っていました(テスト可能ではなく、高いカップリングなど) 。
では、実際にAPIユーザーにクラスのコンストラクターでPermissionManagerインスタンスを渡すように要求する必要がありますか?アプリケーションにPermissionManagerインスタンスを1つだけ存在させたいのですが、
またはこれについてすべて間違っていますか?非公開コンストラクタと、PermissionManagerのインスタンスを渡すファクトリが必要ですか?
追加情報「依存性注入」と言うとき、DI パターン ... GuiceやSpringなどのDIフレームワークは使用していません。 (...まだ)
解決
依存関係注入フレームワークを使用している場合、これを処理する一般的な方法は、コンストラクターでPermissionsManagerオブジェクトを渡すか、フレームワークが設定するPermissionsManager型のプロパティを取得することです。
これが実行可能でない場合、ユーザーにファクトリを介してこのクラスのインスタンスを取得させることは良い選択です。この場合、ファクトリーはクラスを作成するときにPermissionManagerをコンストラクターに渡します。アプリケーションの起動時に、最初に単一のPermissionManagerを作成し、次にファクトリを作成してPermissionManagerを渡します。
クラスのクライアントが正しいPermissionManagerインスタンスを見つけてそれを渡す場所を知ること(または、クラスがPermissionManagerを使用するという事実を気にすることさえ)が通常扱いにくいことは正しいです。
私が見た妥協案の1つは、クラスにPermissionManager型のプロパティを与えることです。プロパティが設定されている場合(ユニットテストなど)、そのインスタンスを使用します。それ以外の場合はシングルトンを使用します。次のようなもの:
PermissionManager mManager = null;
public PermissionManager Permissions
{
if (mManager == null)
{
return mManager;
}
return PermissionManager.getInstance();
}
もちろん、厳密に言うと、PermissionManagerはある種のIPermissionManagerインターフェースを実装する必要があります。また、テスト中にダミーの実装をより簡単に置き換えることができるように、他のクラスが参照する必要がある
他のヒント
PermissionManagerを注入することで、実際に開始できます。これにより、クラスのテストが容易になります。
これにより、そのクラスのユーザーに問題が発生した場合、ファクトリーメソッドまたは抽象ファクトリーを使用させることができます。または、テストでPermissionManagerのモックに使用できる別のコンストラクターを使用している間に、PermissionManagerを挿入する呼び出しを行うパラメーターなしのコンストラクターを追加できます。
クラスをさらに分離すると、クラスがより柔軟になりますが、使用が難しくなります。状況によって異なります。 PermissionManagerが1つしかなく、それを使用するクラスのテストに問題がない場合、DIを使用する理由はありません。人々が独自のPermissionManager実装を追加できるようにしたい場合は、DIが最適です。
依存性注入の方法をサブスクライブしている場合、 PermissionManager
が必要なクラスはすべて、オブジェクトインスタンスとして注入する必要があります。 (シングルトンの性質を強制するために)インスタンス化を制御するメカニズムは、より高いレベルで機能します。 Guiceのような依存性注入フレームワークを使用している場合は、施行作業を実行できます。オブジェクトの配線を手作業で行う場合、依存性注入は、ビジネスロジックからインスタンス化(新しいオペレーターの作業)を行うコードのグループ化を優先します。
どちらの方法でも、古典的な「capital-S」はシングルトンは一般に、依存性注入のコンテキストではアンチパターンと見なされます。
これらの投稿は過去に私にとって洞察力がありました:
では、実際にAPIユーザーにクラスのコンストラクターでPermissionManagerインスタンスを渡すように要求する必要がありますか?アプリケーションにPermissionManagerインスタンスを1つだけ存在させたいのですが、
はい、あなたがする必要があるのはこれだけです。依存関係がシングルトン/リクエストごと/スレッドごとまたはファクトリメソッドであるかどうかは、コンテナと構成の責任です。 .netの世界では、カップリングをさらに減らすためにIPermissionsManagerインターフェイスに依存するのが理想的です。これはJavaでもベストプラクティスだと思います。
シングルトンパターン自体は悪くはありません。見苦しいのは、特定のクラスの単一のインスタンスのみが必要なため、一般的に使用される方法です。これは大きな間違いだと思います。
この場合、何らかの理由でインスタンス化可能な型である必要がない限り、PermissionManagerを静的クラスにします。