最近、Service Locatorのアンチパターンに関するMark Seemannの記事を読みました。
著者は、ServiceLocatorがアンチパターンである2つの主な理由を指摘しています。
APIの使用に関する問題(これで問題
ありません)クラスがサービスロケーターを使用する場合、ほとんどの場合、クラスにはPARAMETERLESSコンストラクターが1つしかないため、依存関係を確認することは非常に困難です。ServiceLocatorとは対照的に、DIアプローチは、コンストラクターのパラメーターを介して依存関係を明示的に公開するため、IntelliSenseで依存関係を簡単に確認できます。メンテナンスの問題(これは私を困惑させます)
次の例を考えます
サービスロケーターアプローチを採用するクラス'MyType'があります。
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
}
}
次に、クラス 'MyType'に別の依存関係を追加します
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
// new dependency
var dep2 = Locator.Resolve<IDep2>();
dep2.DoSomething();
}
}
そして、ここが私の誤解の始まりです。著者は言う:
重大な変更を導入しているかどうかを判断するのは非常に難しくなります。Service Locatorが使用されているアプリケーション全体を理解する必要がありますが、コンパイラーは役に立ちません。
しかし、少し待ってください。DIアプローチを使用している場合は、コンストラクターに別のパラメーターとの依存関係を導入します(コンストラクターインジェクションの場合)。そして、問題はまだそこにあります。ServiceLocatorのセットアップを忘れた場合は、IoCコンテナーに新しいマッピングを追加し忘れた可能性があり、DIアプローチでも同じランタイム問題が発生します。
また、著者はユニットテストの難しさについて言及しました。しかし、DIアプローチに問題はありませんか?そのクラスをインスタンス化していたすべてのテストを更新する必要はありませんか?テストをコンパイル可能にするために、新しいモック依存関係を渡すようにそれらを更新します。そして、私はその更新と時間の浪費から何の利益も見ていません。
私はService Locatorのアプローチを擁護するつもりはありません。しかし、この誤解により、私は非常に重要な何かを失っていると思います。誰かが私の疑問を払拭できますか?
更新(要約):
「Service Locatorはアンチパターンですか?」という私の質問に対する答えは、実際には状況によって異なります。そして、私はあなたのツールリストからそれを取り除くことを絶対に勧めません。レガシーコードの処理を開始すると、非常に便利になる場合があります。幸運にもプロジェクトの最初の段階にいる場合、Service Locatorに比べていくつかの利点があるため、DIアプローチの方が適している可能性があります。
そして、ここに私の新しいプロジェクトにService Locatorを使用しないと確信した主な違いがあります:
- 最も明白で重要:Service Locatorはクラスの依存関係を隠します
- IoCコンテナーを利用している場合、起動時にすべてのコンストラクターをスキャンしてすべての依存関係を検証し、欠落しているマッピング(または誤った構成)に関するフィードバックを即座に提供します。IoCコンテナーをサービスロケーターとして使用している場合、これは不可能です
詳細については、下記の優れた回答をご覧ください。