当使用接口或抽象类? 当同时使用?(When to use interfaces or abst

2019-06-18 01:12发布

虽然某些准则规定,你应该当你要定义一个类合同在那里继承不明确(使用接口IDomesticated当类是另一个的扩展)和继承( Cat : MammalSnake : Reptile ),有当(在我看来)情况下,这些准则进入一个灰色地带。

例如,说我的执行是Cat : PetPet是一个抽象类。 应该说是扩大到Cat : Mammal, IDomesticated其中Mammal ,是一个抽象类IDomesticated是一个接口? 还是我与冲突KISS / YAGNI原则(尽管我不知道是否还会有Wolf在未来的类,它不能够继承Pet )?

移动从隐喻走Cat S和Pet S,让我们说我有一些类,代表了输入数据源。 他们都需要以某种方式实现相同的基础。 我可以实现在一个抽象的一些通用的代码Source类,并从它继承。 我也可以只让一个ISource接口(其中感觉更“正确”对我来说),并重新实现在每一类中的通用代码(这是不太直观)。 最后,我可以“有鱼和熊掌兼得”使两个抽象类和接口。 什么是最好的?

这两种情况带来了点,仅使用一个抽象类,只有一个接口,同时使用抽象类和接口。 难道这些都有效的选择,还是有“规矩”时,应该对另一用途?


我想用“同时使用抽象类和接口”,包括当他们基本上代表了同样的事情(的情况下,以澄清SourceISource都具有相同的成员),但类添加通用功能,而接口指定合约。

另外值得一提的是,这个问题主要是为那些不支持多重继承(如.NET和Java)的语言。

Answer 1:

作为一个经验的第一条规则,我更喜欢抽象类通过接口, 基于.NET设计准则 。 该推理也适用比.NET宽得多,但在这本书是更好地解释框架设计指南 。

偏爱抽象基类背后的主要理由是版本控制,因为你可以一个新的虚拟成员总是添加到一个抽象基类,而不会破坏现有的客户。 这是不可能的接口。

还有场景中的接口仍然是正确的选择(特别是当你不关心版本),但意识到的优点和缺点,使您能够做出正确的决定。

因此,作为一个局部的答案之前,我继续:具有输入接口和一个基类,如果你决定编写针对在首位的接口才有意义。 如果允许的接口,你必须编写只针对该接口,因为否则的话,你就违反了里氏替换原则。 换句话说,即使你提供一个实现该接口的基类,你不能让你的代码消耗基类。

如果您决定编写针对一个基类,具有接口是没有意义的。

如果您决定对代码的接口,具有基础类,提供默认功能是可选的。 这是没有必要的,但可能会加快东西实施者,所以你可以提供一个出于礼貌。

该弹簧想到的一个例子是在ASP.NET MVC。 请求管道工程对一个IController,但有您通常使用来实现行为Controller基类。

最终的答案:如果使用一个抽象基类,只能使用。 如果使用的接口,一个基类是一个可选的礼貌实施者。


更新:不再喜欢抽象类在接口和我没有很长一段时间; 相反,我喜欢在继承组成,采用固体作为指导。

(虽然我可以直接编辑上面的文字,它会从根本上改变职位的性质,并且因为很多人都认为它足够的有价值赞成票的话,我宁愿让原始文本的立场,而是添加此注意,帖子的后半部分仍然是有意义的,所以这将是一种耻辱,把它删除了。)



Answer 2:

我倾向于使用基类(抽象的或不)来描述的东西什么,而我使用接口来描述一个物体的能力

是猫哺乳动物,但它的功能之一是,它是Pettable。

或者,把它用不同的方式,类名词,而接口映射接近形容词。



Answer 3:

从MSDN, 对于抽象类与接口的建议

  • 如果预计创建组件的多个版本,创建一个抽象类。 抽象类提供了一个简单易用的方式,以版本的组件。 通过更新基类,所有继承类自动与变化更新。 接口方面,在另一方面,不能创建一次改变。 如果需要接口的新版本,必须创建一个全新的接口。

  • 如果您正在创建的功能将在大范围不同对象的有用,使用的接口。 抽象类应主要用于密切相关的对象,而接口最适合于不相关的类提供通用功能。

  • 如果你正在设计的功能性小,简洁位,使用接口。 如果你正在设计大的功能单元,则使用抽象类。

  • 如果你想提供共同,实现你的组件的所有实现中的功能,使用抽象类。 抽象类允许部分实现类,而接口包含的任何成员没有实现。



Answer 4:

如果你想提供完全免去您实现的选项,使用的接口。 这尤其适用于主要部件之间的相互作用,这些应该始终被分离的接口。

也有可能是prefering的接口,例如,使嘲弄在单元测试中的技术原因。

在内部组件,可能被罚款,只是使用抽象类直接访问类层次。

如果您使用的接口,并具有实现类的层次结构那么它是很好的做法,包含实施的公用部分的抽象CLASSE。 例如

interface Foo
abstract class FooBase implements Foo
class FunnyFoo extends FooBase
class SeriousFoo extends FooBase

你也可以有更多的抽象类互相继承了更复杂的层次。



Answer 5:

我总是用这些准则:

  • 多类型继承使用接口(如.NET / Java的不使用多重继承)
  • 使用抽象类的类型的可重复使用的实施

占主导地位的关注的规则指明一个类总是有一个主要的关注和0或多个其他(见http://citeseer.ist.psu.edu/tarr99degrees.html )。 那些0以上的人,你再通过接口来实现,作为类则实现了所有它必须实现类型(其本身而言,它实现所有接口)。

在实现多继承的世界(例如,C ++ /艾菲尔),人们会从中实现的接口类继承。 (理论上,在实践中可能无法正常工作那么好。)



Answer 6:

还有一种叫做DRY原则-不重复自己。

在数据源的例子,你说有一些通用的代码,不同的实现之间的共同。 对我来说,似乎来处理,最好的办法是将有与它的通用代码和扩展它的一些具体类的抽象类。

其优点是,在通用的代码在每个bug修正有益于所有具体实现。

如果你去接口只,你将不得不保持其是自讨苦吃同一代码的多个副本。

关于抽象的+接口,如果它没有直接的理由,我不会去做。 从抽象类中提取接口是一个简单的重构,所以我会做它,只有当实际需要它。



Answer 7:

请参阅下面的一般准则SE问题:

接口VS抽象类(一般OO)

实际使用情况的界面:

  1. 实施Strategy_pattern :定义你的战略,作为一个接口。 在运行时策略的具体实现的一个动态切换的实现。

  2. 定义多个不相关的类中的能力

实际使用情况的抽象类:

  1. 实施Template_method_pattern :定义一个算法的骨架。 子类不能改变algortihm的strucutre但他们可以重新定义子类中的实现的一部分。

  2. 当你想多个相关类与之间共享非静态和非最终变量“ 有一个 ”关系。

既abstradt类和接口的使用:

如果你想为一个抽象类,您可以将抽象方法的接口和抽象类可以简单地实现该接口。 抽象类的所有用例可以归入此类。



文章来源: When to use interfaces or abstract classes? When to use both?