一个接口是否应该继承另一个接口


71

我似乎找不到答案,只是想确保它是一个好的编码标准。我有A许多不同类使用的接口,并且不想A更改接口。我遇到了一个新的要求,该要求将要求许多实现Interface的类都需要一个枚举A,但是并非所有的类都需要该枚举。我不希望不需要此新枚举的类实现此新功能。因此,我创建B了包含需要添加的新枚举的接口。然后,我使接口B继承接口A,这是我关心的问题,一个接口可以继承另一个接口吗?为了继续进行更改,然后更改了需要新枚举实现接口的类。B而不是interface,A因为它是由interface继承的B。我考虑过在需要它们的类中实现这两个接口,但是我在整个代码中都使用该接口,并且只想使用一个接口浏览类,而不要使用两个接口。

我希望这已经足够清楚(可能很长),但是如果有人可以给我一些建议,或者我做对了或者我做错了,请告诉我。

谢谢!

Answers:


80

接口继承是一个很好的工具,尽管您仅应在接口B真正可替代接口A时使用它,而不仅仅是汇总松散相关的行为。

很难确定它是否适合您的特定情况,但是原则上使用该实践没有错。您始终可以在一流的API中看到它。仅从.NET框架中选择一个常见示例:

public interface ICollection<T> : IEnumerable<T>, IEnumerable

2
我最初建议应采用Liskov替代原则。回想起来,这并不重要。LSP的大多数要求(保持不变性,对前置条件和后置条件的限制)实际上仅适用于具体实现,而不适用于接口。话虽如此,可替换性的一般原则仍应指导接口继承决策。
Jeff Sternal

Liskov替换原则:确保接口B可以完全替换接口A是很重要的。否则,您将获得必须实现的功能,这些功能是您不需要的。这会导致您不需要多余的代码,从而使软件不稳定。
乍得·克罗

我发现当用外观代替现有的依赖关系时,它可以很好地工作,现在需要第二个实现。无需更改原始类和所有需要工厂的测试,Facade会使用工厂进行处理并返回所需的结果。我使用标记器接口将两个不同的接口注入到立面将要使用的工厂中。只有工厂知道“标记”接口。这并不理想,但是与更改现有类相比,我更喜欢它。
DanCaveman

21

考虑一下接口是否应该在逻辑上配对,并且如果您认为它们可以很好地相互配合,则绝对使用继承。

让我们看一个例子;

public interface IScanner
{
    void Scan();
}

public interface IPrinter
{
    void Print();
}

打印机和扫描仪通常是独立的对象,每个对象都有各自的功能,但是,这两个设备通常配对在同一设备上。

public interface IPhotocopier : IScanner, IPrinter
{
    void Copy();
}

IPhotocopier应该继承自IScanner和IPrinter是有道理的,因为它现在可以使复印机除了作为复印机的主要卷筒之外,还可以用作扫描仪或打印机(包含)。

现在让我们再看一个界面;

public interface IBlender
{
    void Blend();
}

允许IBlender被任何早期接口(您称它们为IBlendingScanner?)继承都是没有意义的。

如果您不能给新接口起一个合理的名称,则可能表明您可能不想在这种情况下使用继承。

继承一些接口(例如IDisposable)是一个坏主意,因为这会迫使新接口的所有实现都实现处置模式,即使它们没有任何可使用的资源。


12

从技术上讲,接口不会相互继承。当创建一个IFoo继承自它的东西时,实际上IBar是在说什么实现的类也IFoo必须实现IBar

interface IBar
{
    void DoBar();
}

interface IFoo : IBar
{
    void DoFoo();
}

在此示例中,IFoo接口没有DoBar()方法。在大多数情况下,区别并不重要,但是在接口而不是类上使用反射时,它可能会咬人。


5
即使考虑到您描述的行为(在Phil Haack的最新专栏haacked.com/archive/2009/11/10/…中进行了详细的描述),我仍然认为将“接口彼此之间不继承”的做法令人不解当C#参考文档甚至使用该术语时,也称为C#,例如“接口可以从一个或多个基本接口继承”。(msdn.microsoft.com/zh-cn/library/87d83y5b%28VS.80%29.aspx)我只想说,在C#中,当反映继承的成员时,接口继承的行为不同于类继承。
杰夫·斯特恩

1
很公平。我猜这取决于如何定义“继承”。当然,无论是类还是接口,C#语法都是相同的。但是,如果您认为继承包含父项的成员,那么当您谈论接口时,您的心理模型就与现实不符。
乔尔·穆勒

6

当然,可能有一个接口的继承树,甚至带有接口的“多重继承”。做对与否取决于所讨论的接口。如果确实是接口B是接口A的扩展或细化,则继承是有意义的,但是如果新枚举与接口A所表达的概念在很大程度上无关,我将使它们成为两个单独的接口并具有类需要同时实现这两个接口。


3

IMO这是正确的方法,我认为它没有任何问题。


2

我认为数据库总是提供一种很好的方式来演示接口,因此考虑一个接口是否应该继承另一个接口,请看下面的内容,

IMySqlDatabase : IDatabase
MySqlDatabase : IMySqlDatabase

IMsSqlDatabase : IDatabase
MsSqlDatabase : IMsSqlDatabase

MySqlDatabase是IMySqlDatabase,而IMySqlDatabase是IDatabase。

现在,如果您需要对IDatabase接口进行更改,那么孙辈(数据库类)可以从中受益,但是您不必扩展MySQL和MsSQL(甚至可能扩展更多的DBMS接口)。同时,在您的中间人(IMsSqlDatabase)中,您仍然可以具有MySQL或Oracle DB不支持的接口功能。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.