これを解決する最善の方法は、おそらくインターフェイスで agentId を要求し、ABC と DEF の場合はそれを必要としない場合は単純に無視することです。そうすれば、消費するクラスはまだ違いを知りません。
実際、ABC、DEF、および XYZ プロバイダーを交換可能に使用する場合に最も重要なのは、Liskov Substitution Principle です。「クラスXに依存するクラスAが与えられた場合、Xは違いを知らなくても、Aから派生したクラスBを使用できるはずです」。
インターフェイス分離の原則は、基本的に、インターフェイスには、そのコンシューマーのいずれも必要としないメンバーを含めるべきではないと述べています。これらのメンバーの定義が変更された場合、そのメソッドを使用していないクラスも再コンパイルする必要があるためです。彼らが依存していたものは変化しました。これは関連していますが (オーバーロードを追加する場合は IServiceProvider のすべてのコンシューマーを再コンパイルする必要があります)、Authenticate() の署名を変更する場合はとにかくそれを行う必要があります。 Authenticate() のオーバーロードを追加したので、消費者はどのオーバーロードを使用する必要があるかを知る必要があります。そのためには、LSP に違反して、共通のインターフェイスの実装の違いを消費するクラスが認識している必要があります。これ' 特定のプロバイダーが必要とする以上の情報を提供しても問題はありませんが、2 つの入力しか提供しない用途から XYZ を使用すると問題が発生します。これらの問題を回避するには、常に 3 つのパラメーターのオーバーロードを使用します。
現在、IServiceProvider の現在の使用が、agentId を持たず、気にしない領域で行われているため、それを提供し始めるのが難しい場合は、具体的な XYZ プロバイダーがプラグインし、実装するアダプターをお勧めします。現在の IServiceProvider を作成し、別の方法で agentId を提供することで、新しいプロバイダーを古いプロバイダーのように機能させます。
public class XYZAdapter: IServiceProvider
{
private readonly XYZServiceProvider xyzProvider;
public XYZAdapter(XYZServiceProvider provider)
{
xyzProvider = provider;
}
public void Authenticate(string username, string password)
{
xyzProvider.Authenticate(username, password, GetAgentId());
}
public int GetAgentId()
{
//Retrieve the proper agent Id. It can be provided from the class creator,
//retrieved from a known constant data source, or pulled from some factory
//method provided from this class's creator. Any way you slice it, consumers
//of this class cannot know that this information is needed.
}
}
これが可能であれば、LSP と ISP の両方を満たします。LSP をサポートするためにインターフェイスを変更する必要がないため、ISP が一般的に回避しようとするシナリオ (依存関係の再コンパイルと再配布) を防ぐことができます。ただし、クラス数が増加し、アダプターの新しい機能が必要な agentId を正しく取得するように強制されます。その依存関係は、IServiceProvider インターフェイスを介して認識できないものを提供する必要はありません。