2012-02-07 11 views
5

.netでは、基本クラスでの部分的なインターフェイス実装が許可されていません。緩和策として、私は3つの代替ソリューションを用意しました。リファクタリング、コンパイル/ランタイムエラー、可読性の点で、より普遍的なものを決定するのを手伝ってください。 最初にいくつかのコメント。基本クラス/抽象クラスでのC#最適な部分インターフェイス実装

  • もちろん、オブジェクトをIFooにキャストし、コンパイラの警告なしで任意のメソッドを呼び出すことができます。しかし、それは論理的ではありません、あなたはそれを普通にやりません。この構成は、リファクタリングの結果としては起こりません。
  • 最大限の分離が必要です。直接クラス契約(パブリックメソッドとプロパティ)は、インタフェースの実装と分離する必要があります。私はオブジェクトインターアクションを分離するためにインターフェイスを多く使用しています。

マイ比較:

  1. BaseClass1/MyClass1:
    • 詐欺:IFooのそれぞれ実装されていないメソッドのBaseClass1で仮想抽象を作成する必要があります。
    • con:追加メソッドのラップ - 実行時のわずかな生産性への影響。
  2. BaseClass2/MyClass2:
    • 詐欺:MyClass2における方法2の無実装がない場合はコンパイラの警告。代わりにランタイム例外。ユニットテストのカバレッジが悪いリファクタリングは、コードを不安定にする可能性があります。
    • con:子クラスからの直接的なメソッド呼び出しを防ぐために、廃止された構造体を追加する必要があります。
    • con:Method2はBaseClass1のため公開されているので、今はclass contractの一部です。 IFoo経由ではなく、直接呼び出しを防ぐために「廃止」構造体を置かなければなりません。
  3. BaseClass3/MyClass3:
    • プロ:(#2と比較すると)。より読みやすい。 MyClass2.Method2はオーバーライドされたメソッドだけでなく、IFooの実装であることがわかります。
public interface IFoo 
{ 
    void Method1(); 
    void Method2(); 
} 
public abstract class BaseClass1 : IFoo 
{ 
    void IFoo.Method1() 
    { 
     //some implementation 
    } 

    void IFoo.Method2() 
    { 
     IFooMethod2(); 
    } 

    protected abstract void IFooMethod2(); 
} 

public class MyClass1 : BaseClass1 
{ 
    [Obsolete("Prohibited direct call from child classes. only inteface implementation")] 
    protected override void IFooMethod2() 
    { 
     //some implementation 
    } 
} 
public abstract class BaseClass2 : IFoo 
{ 
    void IFoo.Method1() 
    { 
     //some implementation 
    } 

    [Obsolete("Prohibited direct call from child classes. only inteface implementation")] 
    public virtual void Method2() 
    { 
     throw new NotSupportedException(); 
    } 
} 

public abstract class MyClass2 : BaseClass2 
{ 
    public override void Method2() 
    { 
     //some implementation 
    } 
} 
public abstract class BaseClass3 : IFoo 
{ 
    void IFoo.Method1() 
    { 
     //some implementation 
    } 

    void IFoo.Method2() 
    { 
     throw new NotSupportedException(); 
    } 
} 

public abstract class MyClass3 : BaseClass3, IFoo 
{ 
    void IFoo.Method2() 
    { 
     //some implementation 
    } 
} 
+6

これは、実装しようとしている**非常に厄介なパターンです。あなたが言った* "。NETは基本クラスで部分的なインターフェイスの実装を許可していません" * - その理由があります。クライアントコードの種類は、**インターフェース**を実装しているものがあります。おそらく... **インターフェースを実装しています**。サポートされていないメソッドの例外をスローすることは、もちろんです。*非常に*悪いコードの臭いです... – Yuck

+0

Yuckと同意します。あなたが 'IFoo'型の変数を持っているなら、実際には' IFoo'のすべてのメソッドが実装され、利用可能であると期待しています。そのためのインターフェースが作られています。 – ken2k

+0

MyClass1のみがインターフェイスを完全に実装している必要があります。それはそうです。問題は、複数の子クラスがあることです(私はこれまで言及していませんでした)、それぞれIFooを実装する必要があります。基本クラスがなければ、Method1の実装をコピー/貼り付けする必要があります。これはすべての子クラスに対して等しくなります。これは私が避けようとしていることです。しかし、Method2実装は子クラスでは異なるので、Method1とMethod2の両方を実装するクラスを1つだけ持つことはできません。 – user1194528

答えて

5

[OK]を、あなたはBaseClassとして次のことを試みることができる抽象的です:

public interface IFoo 
{ 
    void Method1(); 

    void Method2(); 
} 

public abstract class BaseClass : IFoo 
{ 
    public void Method1() 
    { 
     // Common stuff for all BaseClassX classes 
    } 

    // Abstract method: it ensures IFoo is fully implemented 
    // by all classes that inherit from BaseClass, but doesn't provide 
    // any implementation right here. 
    public abstract void Method2(); 
} 

public class MyClass1 : BaseClass 
{ 
    public override void Method2() 
    { 
     // Specific stuff for MyClass1 
     Console.WriteLine("Class1"); 
    } 
} 

public class MyClass2 : BaseClass 
{ 
    public override void Method2() 
    { 
     // Specific stuff for MyClass2 
     Console.WriteLine("Class2"); 
    } 
} 

private static void Main(string[] args) 
{ 
    IFoo test1 = new MyClass1(); 
    IFoo test2 = new MyClass2(); 

    test1.Method2(); 
    test2.Method2(); 

    Console.ReadKey(); 
} 
+0

これは第1の欠点を除いて私の変種#2です。依然として適用されます:1.子クラスからの直接メソッド呼び出しを防ぐために、不要な構造を追加する必要があります。あなたのケースではObsoleteは存在しないので、子クラスからのダイレクトコールはコンパイル時に警告2を生成しません。Method2はBaseClass1のために公開されるので、今はclass contractの一部です。 IFoo経由ではなく、直接呼び出しを防ぐために「廃止」構造体を置かなければなりません。 3.読みにくい。 Method2がIFooの実装であることはわかりません。 – user1194528

+0

質問の下のコメントを読むと、これは問題を解決する正しい方法のようです。 '' BaseClass'で '方法2()の抽象実装が同時に'方法2を() '実装するBaseClass''由来するすべてのクラスを強制しながら 'IFoo'が完全に実現されることを保証します。派生クラスは 'Method1()'をオーバーライドすることはできませんが( 'new'キーワードを使って)それを隠すことができるようになります。 – Nailuj

+0

@ user1194528上記のコードの実際の問題は何ですか?なぜ廃止された注釈を挿入したいのですか? – ken2k

6

doesnのクラスを設計することは非常に悪いです明確な定義を実装していないd契約。あなたが最初にクラスが何かをすることができると言うので、それは極端です。あなたは明示的にクラスのことができることを強調していますが、後でコードであなたはナーを言う、それをねじ込む、このクラスは実装することなく生きることができます。コンパイラは非常に賢明にあなたに契約を実行するように頼んでいますが、決定するのはあなた次第です。ここで

いくつかの一般的なソリューションは

  • sampleを参照してください、NonImplementedExceptionまたは非サポート例外)例外をスロー

    バート・ソリューション

    • されている、それは時代遅れとして宣言します(最初から良い、それを設計)

    Betterソリューション

    • 明示的なインターフェイスの実装、しかし、あなたはまだベストソリューション

    (だけの種類のそれを隠す)

    • 使用インタフェースの分離をそれを実装(シンナーにあなたの脂肪インターフェイスを分割より管理しやすいもの)
  • +1

    私はインターフェースの分離を考えましたが、問題はインターフェースの設計がサーバークラスではなくクライアントクラスのニーズから来ていることです。クライアントクラスは実装の詳細を知りたくありません。なぜこのインタフェースが基本クラスで実装されているのか、他の実装が子プロセスで実装されているのかを知る必要がありますか?また、非常に壊れやすく、このインターフェースを実装する2つのクラス階層があり、基本クラスと子クラスの間で実装がどのように分割されるかは異なります。 – user1194528

    0

    抽象基本クラスにprotected abstractメソッドを呼び出すメソッドを持つインターフェイスを実装することをお勧めします。いくつかの派生クラスは実装しないメソッドを除いて、最初の例に示したように(「すべてをIListにスローしますが、すべてのメソッドは実際に "パターン"で動作します)。それらはprotected virtualスタブでNotSupportedExceptionを投げることができます。

    インターフェイスの特定のメンバーを同じ名前のパブリックメンバー(適切な抽象メンバーを呼び出すことができる)として公開するかどうかは、子クラスによって異なります。

    VB.netの適切なパターンは、MustOverride Sub IFoo_Method1() Implements IFoo.Method1のようになります。これは、関数呼び出しのオーバーヘッドを避けることができますが、C#は保護されたメンバとのインターフェイスを実装する手段を提供しません。子クラスでオーバーライドする必要のあるメソッドの明示的なインターフェイス実装を使用することは多少厄介です。なぜなら、子のインターフェイスの再実装が親の実装に連鎖することは不可能だからです。

    +0

    >>親の実装に連鎖するインターフェースの子の再実装は不可能です。 - いい視点ね。このような観点から、すべてのメソッドを保護されたものとして宣言する方が良い(実装されていない場合は+抽象的である)(ken2kの亜種)。ありがとうございました。今私は情報に基づいた意思決定をすることができます。 – user1194528

    8

    私はこのバージョンが好きです。その抽象クラス、派生クラスはその宣言にIFooをリストする必要があります。そうしないと、インターフェイスを実装しておらず、残りを実装するだけですインターフェイスの 私が見ることができる1つの欠点は、基本クラス(つまりIFoo:Method1なし)でインターフェイスメソッドを明示的に実装できないことです。それ以外の場合はかなり低いオーバーヘッドバージョンです。

    public interface IFoo 
    { 
        void Method1(); 
        void Method2(); 
    } 
    
    public abstract class BaseClass1 
    { 
        public void Method1() 
        { 
         //some implementation 
        } 
    } 
    
    public class MyClass1 : BaseClass1, IFoo 
    { 
        public void Method2() 
        { 
         //some implementation 
        } 
    } 
    
    関連する問題