如何避免重复的接口代码?

O.O*_*O.O 14 c# oop refactoring

由于接口不能包含实现,因此在我看来,这会导致从接口继承的类中的代码重复.在下面的示例中,假设,假设从流中设置读取的前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
    }
}
Run Code Online (Sandbox Code Playgroud)

我意识到使用ProcessData的抽象基类并添加非抽象成员是一种解决方案.但是,如果我真的真的想要使用界面呢?

Lev*_*son 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
    }
}
Run Code Online (Sandbox Code Playgroud)

语法可能有点偏,我不是普通的C#用户.我是通过OOP标签来到这里的.


das*_*ght 14

跨接口共享代码的最佳方式是通过无状态扩展方法.您可以构建一次这些扩展,并在实现该接口的所有类中使用它,而不管它们的继承链如何.这就是.NET IEnumerable<T>在LINQ中所做的,取得了相当令人印象深刻的结果.这种解决方案并非总是可行,但您应该尽可能地选择它.

另一种共享逻辑的方法是创建一个内部"帮助器"类.在您的情况下,这看起来是正确的选择:实现可以将内部共享代码作为帮助程序的方法调用,而无需复制任何代码.例如:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

辅助类不需要是静态的:如果您的共享方法需要状态,您可以使您的帮助程序成为常规类,并将其实例放在您希望共享代码的接口的每个实现中.

  • @OO如果你确实需要状态,你当然可以使你的助手类非静态.这使您的继承层次结构从继承抽象基础的需要中解放出来,有效地用包含(私有)替换继承(公共). (3认同)
  • 我认为这是最好的解决方案.一个抽象基类在当时似乎是个好主意......直到你需要实现第二个接口.你不会从另一个基类继承! (2认同)