web-dev-qa-db-ja.com

インターフェースは他のインターフェースを拡張する必要があります(そうすることで他のインターフェースを継承します)

これは一般的な質問ですが、私が現在経験している問題にも固有のものです。私は現在、私のソリューションで指定されたインターフェイスを

public interface IContextProvider
{
   IDataContext { get; set; }
   IAreaContext { get; set; }
}

このインターフェイスはプログラム全体でよく使用されるため、必要なオブジェクトに簡単にアクセスできます。しかし、私のプログラムの一部のかなり低いレベルでは、IAreaContextを使用し、それからいくつかの操作を実行する別のクラスにアクセスする必要があります。そこで、この作成を行うための別のファクトリインターフェースを作成しました。

public interface IEventContextFactory 
{
   IEventContext CreateEventContext(int eventId);
}

IContextProviderを実装し、NinJectを使用して注入されるクラスがあります。私が持っている問題は、これを使用する必要がある領域IEventContextFactoryIContextProviderのみで、それ自体がこの新しいインターフェースを必要とする別のクラスを使用します。 インスタンス化この実装のIEventContextFactoryを低レベルで実行したくないので、IEventContextFactoryインターフェイス全体。ただし、コンストラクターを介して別のパラメーターを挿入するだけで、それを必要とするクラスに渡される必要はありません。

// example of problem
public class MyClass
{
    public MyClass(IContextProvider context, IEventContextFactory event)
    {
       _context = context;
       _event = event;
    }

    public void DoSomething() 
    {
       // the only place _event is used in the class is to pass it through
       var myClass = new MyChildClass(_event);
       myClass.PerformCalculation();      
    }
}

だから私の主な質問は、これは受け入れられるのか、それともこのようなことをするのが一般的または良い習慣であるのか(インターフェイスが別のインターフェイスを拡張する):

public interface IContextProvider : IEventContextFactory

または私が必要なものを達成するためのより良い代替案を検討する必要があります。提案を提供するのに十分な情報を提供していない場合は、お知らせください。さらに情報を提供できます。

13
dreza

インターフェースは実装なしで動作のみを記述しますが、継承階層に参加できます。例として、Collectionの一般的な考え方があるとします。このインターフェイスは、メンバーを反復処理するメソッドなど、すべてのコレクションに共通するいくつかの機能を提供します。次に、ListSetなど、より具体的なオブジェクトのコレクションについて考えることができます。これらはそれぞれ、Collectionの動作要件をすべて継承しますが、特定のタイプのコレクションに固有の要件を追加します。

インターフェースの継承階層を作成することが理にかなっているときはいつでも、そうする必要があります。 2つのインターフェースが常に一緒に見つかる場合は、おそらくそれらをマージする必要があります。

10
Zoe

はい、しかしそれが理にかなっている場合に限ります。次の質問を自問してみてください。1つ以上が当てはまる場合は、別のインターフェースを継承することもできます。

  1. インターフェイスAはインターフェイスBを論理的に拡張しますか。たとえば、IListはICollectionに機能を追加します。
  2. インターフェイスAは、別のインターフェイスで既に指定されている動作を定義する必要がありますか。たとえば、整理する必要があるリソースがある場合はIDisposableを実装し、反復できる場合はIEnumerableを実装します。
  3. インターフェイスAのすべての実装には、インターフェイスBで指定された動作が必要ですか?

あなたの例では、それらのいずれにも「はい」とは答えないと思います。あなたはそれを別のプロパティとして追加した方がいいかもしれません:

public interface IContextProvider
{
   IDataContext DataContext { get; set; }
   IAreaContext AreaContext { get; set; }
   IEventContextFactory EventContextFactory { get; set; }
}
6
Trevor Pilley

はい、あるインターフェースを別のインターフェースから拡張することは問題ありません。

特定のケースでそれが正しいことであるかどうかの問題は、2つの間に真の「is-a」関係があるかどうかによって異なります。

有効な「is-a」関係には何が必要ですか?

まず、2つのインターフェース間に実際の違いがある必要があります。つまり、親インターフェースを実装するが、子インターフェースは実装しないインスタンスが必要です。両方のインターフェースを実装しないインスタンスが存在しない、または今後も存在しない場合は、2つのインターフェースをマージする必要があります。

第二に、子インターフェースのすべてのインスタンスは必ず親のインスタンスでなければならないというケースでなければなりません。子インターフェースのインスタンスを作成する(合理的な)ロジックはありません。親インターフェース。

これらの両方が真の場合、継承は2つのインターフェースの正しい関係です。

4

一方のインターフェースalwaysがもう一方を要求/提供したい場合は、先に進みます。私はこれをIDisposibleでいくつかのケースで見ましたが、それは理にかなっています。ただし、一般的には、少なくとも1つのインターフェースが責任ではなく特性のように動作することを確認する必要があります。

あなたの例では、それは明確ではありません。両方が常に一緒になっている場合は、1つのインターフェースを作成します。 1つが常にもう1つを必要とする場合、複数の責任やその他の漏れやすい抽象化の問題につながることが多い「Xと1」の継承について心配します。

1
Telastyn