标记接口实现两个或更多其他接口

时间:2010-10-20 12:40:11

标签: interface

编写仅用于集中其他接口的接口是一种良好的做法还是不好的做法?

interface InterfaceA : InterfaceB, InterfaceC {
}

在这样做时,具体实现只需要实现InterfaceA,这似乎是一件好事,但它不会通过扩展来增加任何价值,这似乎是浪费。

4 个答案:

答案 0 :(得分:2)

我认为这取决于你的域名是否有意义。如果有,我会这样做,然后你的程序会更准确地模拟你的域名。

此外,当然,您现在可以编写需要/使用实现InterfaceA的对象的代码,即两个超级接口的所有方法;以前那是不可能的。

答案 1 :(得分:1)

如果它有意义,并且您将独立使用所有三个接口,那么它肯定是适当的设计决策。

如果事实证明不会使用InterfaceB和IntefaceC,那么只需创建InterfaceA ......

答案 2 :(得分:1)

这对于维护代码可读性确实很有用,然后您可以使用接口A的具体实现,其中需要接口B或C.

答案 3 :(得分:1)

我打算问同样的问题,但我决定保持警惕并做一些广泛的搜索 - 以避免重复。然后我找到了这个 - 我编辑了标题,希望它会变得更受欢迎,因为它应该。

首先,我们应该知道像这样的空接口也称为标记接口 - this other, unanswered, SO discusses concerns marker interfaces和Scott Wisniewsi的回答(目前排名靠前)在考虑我要做的其他事情时很有意思说。

在研究空接口时,您通常偶然发现the MSDN topic concerning Code Analysis warning CA1040,这特别暗示应避免使用至少两个其他接口的空接口。

通过这个标记 - 当然不一定暗示微软的编码指南是事实上的 - 在你的例子中,这正是你正在做的事情(以及我在当前项目中想要做的事情),因此它会通过MS'自己的试金石。因此,我很高兴地说'是的,这样的界面非常合理'。

为了证明理由,我认为一个特别好的例子说明为什么'至少两个接口'开关被置于这个规则上,这与我自己所处的情况类似:

public interface IReadsAResource
{
  public byte[] Read(string id);
}

public interface IWritesAResource
{
  //returns the id
  public string Write(byte[] resource);
}

鉴于这两个接口,我现在可以编写一个明确说明它只需要读或写的组件:

public class NeedsRead
{
  private readonly IReadsAResource Reader;
  public NeedsRead(IReadsAResource reader){ Reader = reader; }
}

public class NeedsWrite
{
  private readonly IWritesAResource Writer;
  public NeedsWrite(IWritesAResource writer){ Writer = writer; }
}

我现在通常会选择在单个类ResourceReaderWriter上实现此接口,因为资源的数据存储将需要两个方法实现共享的依赖项,当任一接口都是需要:

var needsRead = new NeedsRead(new ResourceReaderWriter(/* dependencies */));
var needsWrite = new NeedsWriter(new ResourceReaderWriter(/* dependencies */));

但是如果我有一个类需要同时阅读 写资源呢?有了当前的接口生态系统,我需要两个构造函数参数:

public class NeedsReadAndWrite{
  public NeedsReadAndWrite(IReadsAResource reader, IWritesAResource writer){
    /* reader/writer local variables elided */
  }
}

你可能会说,这并不是一件困难,但却造成了两个问题:

  • 这意味着我们有两个独立的实例负责读写资源;因此,我们的班级不能确定两者是否相互一致。同样,它无法确定两者之间的状态是否正确管理。
  • 作为一个调用者,我当然可以通过先创建一个实例并为两个参数传递它来回避这个问题。但这会剥夺我在单行中创建对象的能力,似乎很奇怪

任何长期坚持我的人都会看到我现在要去的地方:)

优雅的解决方案是为支持阅读写作的类型引入接口:

//denotes a component that can both read and write
public interface IReadsAndWritesAResource : IReadsAResource, IWritesAResource
{

}

使用此界面,我们有问题的类型可以重写为

public class NeedsReadAndWrite{
  public NeedsReadAndWrite(IReadsAndWritesAResource readerWriter){
    /* local variable assignment elided */
  }
}

这两个问题现在都是一步一步的。

同样,通过引入读取器和写入器的实例并将读/写调用转发给那些实现此接口的基本代理类型变得简单。

我认为这个例子说明了为什么你会,或者甚至应该,使用将两个或更多其他人聚集在一起的标记接口。