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


13

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

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

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

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

IContextProviderを実装し、NinJectを使用して注入されるクラスがあります。私が抱えている問題は、このIEventContextFactoryを使用する必要がある領域がIContextProviderにのみアクセスでき、それ自体がこの新しいインターフェイスを必要とする別のクラスを使用することです。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

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


2
インターフェースは実際には何も実装していないため、質問のタイトルを「インターフェースを継承する必要があります」と言い換えます。
ジェシーC.スライサー

2
通常の言語では、インターフェイスは親を「拡張」し、(そうすることで)親インターフェイスのメソッドを「継承」するため、ここで「拡張」を使用することをお勧めします。
セオドアマードック

インターフェースは親を拡張できるのに、なぜそれが悪い習慣になるのでしょうか?1つのインターフェイスが合法的に別のインターフェイスのスーパーセットである場合、もちろんそれを拡張する必要があります。
ロビンウィンスロー

回答:


10

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

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


6

はい、ただしそれが理にかなっている場合のみ。次の質問を自問し、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; }
}

インターフェースを拡張するよりも、どのようにプロパティにするのが良いのでしょうか、それともいわば猫の皮を剥ぐ別の方法でしょうか?
-dreza

1
違いは、あなたが作る場合ということですIContextProvider拡張IEventContextFactoryし、ContextProvider実装は、あまりにもそのメソッドを実装する必要があります。あなたがプロパティとして追加する場合は、と言っているContextProvider持っているIEventContextFactoryが、実際には実装の詳細を知りません。
トレバーピリー

4

はい、あるインターフェイスを別のインターフェイスから拡張しても構いません。

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

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

まず、2つのインターフェイス間に実際の違いがなければなりません。つまり、子インターフェイスではなく親インターフェイスを実装するインスタンスが存在する必要があります。両方のインターフェースを実装していないインスタンスが存在しない場合は、2つのインターフェースをマージする必要があります。

第二に、子インターフェースのすべてのインスタンスは必ず親のインスタンスでなければならないというケースでなければなりません。親インターフェース。

両方が当てはまる場合、継承は2つのインターフェイスの正しい関係です。


派生したインターフェイスではなく、基本インターフェイスのみを使用するクラスは必要ないと思います。たとえば、IReadOnlyListすべてのリストクラスがIList(から派生したIReadOnlyList)実装している場合でも、インターフェイスは便利です。
-svick

1

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

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


ありがとう。責任というよりも特性のように振る舞うということはどういう意味ですか?
dreza

@dreza SOLIDのSRPのような責任を意味し、Scalaの特性のような特性です。主に、インターフェイスが問題をモデル化する方法の概念。それは問題の主要な部分を表しているのか、それとも別の異なるタイプの共通部分に対する見方を表しているのか?
テラスティン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.