14

インターフェイスには実装を含めることができないため、インターフェイスから継承するクラスでコードが重複する可能性があります。以下の例では、たとえば、ストリームからの読み取りを設定する最初の10行ほどが重複していると仮定します。 ここでの表現に焦点を当てるのではなく、各クラス間で重複コードを作成するのがいかに簡単であるかという概念に焦点を当ててください。

例えば:

public interface IDatabaseProcessor
{
   void ProcessData(Stream stream);
}
public class SqlServerProcessor : IDatabaseProcessor
{
    void ProcessData(Stream stream)
    {
      // setting up logic to read the stream is duplicated code
    }
}
public class DB2Processor : IDatabaseProcessor
{
    void ProcessData(Stream stream)
    {
      // setting up logic to read the stream is duplicated code
    }
}

ProcessDataに抽象基本クラスを使用し、非抽象メンバーを追加することが1つの解決策であることに気付きました。しかし、私が本当に、代わりにインターフェースを本当に使用したい場合はどうなりますか?

4

7 に答える 7

18

これは、インターフェイスと抽象基本クラスの両方を使用する場合です。

両方を使用する唯一の理由は、別のクラスが抽象ベースコードを共有せず、インターフェイスを尊重するためです。検討:

public interface IDatabaseProcessor {
   void ProcessData(Stream stream);
}

public abstract class AbstractDatabaseProcessor : IDatabaseProcessor {
    public void ProcessData(Stream stream) {
      // setting up logic to read the stream is not duplicated
    }
}

public class SqlServerProcessor : AbstractDatabaseProcessor {
    //SqlServerProcessor specific methods go here
}

public class DB2Processor : AbstractDatabaseProcessor {
    // DB2Processor specific methods go here
}

public class NonSharedDbProcessor : IDatabaseProcessor {
    void ProcessData(Stream stream) {
      // set up logic that is different than that of AbstractDatabaseProcessor
    }
}

構文が少しずれている可能性があります。私は通常のC#ユーザーではありません。私はOOPタグを介してここに来ました。

于 2012-08-21T21:12:07.647 に答える
14

インターフェイス間でコードを共有する最良の方法は、ステートレス拡張メソッドを使用することです。これらの拡張機能は一度作成すれば、継承チェーンに関係なく、インターフェースを実装するすべてのクラスで使用できます。これは、.NETがIEnumerable<T>LINQで行ったことであり、かなり印象的な結果が得られました。この解決策は常に可能であるとは限りませんが、可能な限りそれを好むべきです。

ロジックを共有するもう1つの方法は、内部の「ヘルパー」クラスを作成することです。これはあなたの場合の正しい選択のように見えます。実装は、コードを複製する必要なしに、ヘルパーのメソッドとして内部共有コードを呼び出すことができます。例えば:

internal static class SqlProcessorHelper {
    public void StreamSetup(Stream toSetUp) {
        // Shared code to prepare the stream
    }
}
public class SqlServerProcessor : IDatabaseProcessor {
    void ProcessData(Stream stream) {
        SqlProcessorHelper.StreamSetup(stream);
    }
}
public class DB2Processor : IDatabaseProcessor {
    void ProcessData(Stream stream) {
        SqlProcessorHelper.StreamSetup(stream);
    }
}

ヘルパークラスは静的である必要はありません。共有メソッドに状態が必要な場合は、ヘルパーを通常のクラスにして、コードを共有するインターフェイスの各実装にそのインスタンスを配置できます。

于 2012-08-21T21:13:23.633 に答える
2

すでに述べたように、1つのオプションは、基本抽象(または非抽象)クラスを使用することです。別のオプションは、共通コードを実行するための別のエンティティを作成することです。あなたの場合、それは可能性がありますDataProcessor

internal class DataProcessor
{
    public void Do(Stream stream) 
    {
        // common processing here
    }
}
public class SqlServerProcessor : IDatabaseProcessor
{
    void ProcessData(Stream stream)
    {
        new DataProcessor().Do(stream);
    }
}
public class DB2Processor : IDatabaseProcessor
{
    void ProcessData(Stream stream)
    {
        new DataProcessor().Do(stream);
    }
}
于 2012-08-21T21:12:56.853 に答える
0

インターフェイスの実装を共有するためのインターフェイスを実装するために、クラスの階層をいくらか持つことは問題ありません。

つまり、あなたの場合、共有ProcessDataコードをのようなものに移動し、両方とそれからProcessorBase派生させることができます。どのレベルがインターフェースを実装するかを決定できます(つまり、何らかの理由でインターフェースを実装するだけで済みます。それでも、インターフェースの実装として基本クラスからProcessDataを取得します)。DB2ProcessorSqlServerProcessorSqlServerProcessorIDatabaseProcessor

于 2012-08-21T21:14:49.357 に答える
0

あなたが示すように、abstractクラスは解決策を提供します。「本当に、本当にしたい」場合は、インターフェイスを使用できます。それを妨げるものは何もありません。クラスabstractはを実装する必要がありますIDatabaseProcessor

于 2012-08-21T21:11:53.967 に答える
0

共有コードからメンバーにアクセスprivateしたり、メンバーにアクセスしたりしながら、基本クラスを本当に使用したくない場合は、コード生成のみを使用できます。組み込みのVS(非常に長い間使用されてきました)であり、非常に強力です。protected

于 2012-08-21T21:12:23.747 に答える
0

抽象基本クラスでインターフェースを使用するだけです。

public interface IDatabaseProcessor
{
   void ProcessData(Stream stream);
}
public abstract class AbstractDatabaseProcessor : IDatabaseProcessor
{
    public virtual void ProcessData(Stream stream)
    {
      // setting up logic to read the stream is duplicated code
    }
}
public class SqlServerProcessor : AbstractDatabaseProcessor
{
    public void ProcessData(Stream stream)
    {
        base.ProcessData(stream);

        // Sql specific processing code
    }
}
public class DB2Processor : AbstractDatabaseProcessor
{
    public void ProcessData(Stream stream)
    {
        base.ProcessData(stream);

        // DB2 specific processing code
    }
}
于 2012-08-21T21:12:31.580 に答える