虽然某些准则规定,你应该当你要定义一个类合同在那里继承不明确(使用接口IDomesticated
当类是另一个的扩展)和继承( Cat : Mammal
, Snake : Reptile
),有当(在我看来)情况下,这些准则进入一个灰色地带。
例如,说我的执行是Cat : Pet
。 Pet
是一个抽象类。 应该说是扩大到Cat : Mammal, IDomesticated
其中Mammal
,是一个抽象类IDomesticated
是一个接口? 还是我与冲突KISS / YAGNI原则(尽管我不知道是否还会有Wolf
在未来的类,它不能够继承Pet
)?
移动从隐喻走Cat
S和Pet
S,让我们说我有一些类,代表了输入数据源。 他们都需要以某种方式实现相同的基础。 我可以实现在一个抽象的一些通用的代码Source
类,并从它继承。 我也可以只让一个ISource
接口(其中感觉更“正确”对我来说),并重新实现在每一类中的通用代码(这是不太直观)。 最后,我可以“有鱼和熊掌兼得”使两个抽象类和接口。 什么是最好的?
这两种情况带来了点,仅使用一个抽象类,只有一个接口,同时使用抽象类和接口。 难道这些都有效的选择,还是有“规矩”时,应该对另一用途?
我想用“同时使用抽象类和接口”,包括当他们基本上代表了同样的事情(的情况下,以澄清Source
和ISource
都具有相同的成员),但类添加通用功能,而接口指定合约。
另外值得一提的是,这个问题主要是为那些不支持多重继承(如.NET和Java)的语言。
作为一个经验的第一条规则,我更喜欢抽象类通过接口, 基于.NET设计准则 。 该推理也适用比.NET宽得多,但在这本书是更好地解释框架设计指南 。
偏爱抽象基类背后的主要理由是版本控制,因为你可以一个新的虚拟成员总是添加到一个抽象基类,而不会破坏现有的客户。 这是不可能的接口。
还有场景中的接口仍然是正确的选择(特别是当你不关心版本),但意识到的优点和缺点,使您能够做出正确的决定。
因此,作为一个局部的答案之前,我继续:具有输入接口和一个基类,如果你决定编写针对在首位的接口才有意义。 如果允许的接口,你必须编写只针对该接口,因为否则的话,你就违反了里氏替换原则。 换句话说,即使你提供一个实现该接口的基类,你不能让你的代码消耗基类。
如果您决定编写针对一个基类,具有接口是没有意义的。
如果您决定对代码的接口,具有基础类,提供默认功能是可选的。 这是没有必要的,但可能会加快东西实施者,所以你可以提供一个出于礼貌。
该弹簧想到的一个例子是在ASP.NET MVC。 请求管道工程对一个IController,但有您通常使用来实现行为Controller基类。
最终的答案:如果使用一个抽象基类,只能使用。 如果使用的接口,一个基类是一个可选的礼貌实施者。
更新:我不再喜欢抽象类在接口和我没有很长一段时间; 相反,我喜欢在继承组成,采用固体作为指导。
(虽然我可以直接编辑上面的文字,它会从根本上改变职位的性质,并且因为很多人都认为它足够的有价值赞成票的话,我宁愿让原始文本的立场,而是添加此注意,帖子的后半部分仍然是有意义的,所以这将是一种耻辱,把它删除了。)
我倾向于使用基类(抽象的或不)来描述的东西是什么,而我使用接口来描述一个物体的能力 。
是猫是哺乳动物,但它的功能之一是,它是Pettable。
或者,把它用不同的方式,类名词,而接口映射接近形容词。
如果你想提供完全免去您实现的选项,使用的接口。 这尤其适用于主要部件之间的相互作用,这些应该始终被分离的接口。
也有可能是prefering的接口,例如,使嘲弄在单元测试中的技术原因。
在内部组件,可能被罚款,只是使用抽象类直接访问类层次。
如果您使用的接口,并具有实现类的层次结构那么它是很好的做法,包含实施的公用部分的抽象CLASSE。 例如
interface Foo
abstract class FooBase implements Foo
class FunnyFoo extends FooBase
class SeriousFoo extends FooBase
你也可以有更多的抽象类互相继承了更复杂的层次。
我总是用这些准则:
- 多类型继承使用接口(如.NET / Java的不使用多重继承)
- 使用抽象类的类型的可重复使用的实施
占主导地位的关注的规则指明一个类总是有一个主要的关注和0或多个其他(见http://citeseer.ist.psu.edu/tarr99degrees.html )。 那些0以上的人,你再通过接口来实现,作为类则实现了所有它必须实现类型(其本身而言,它实现所有接口)。
在实现多继承的世界(例如,C ++ /艾菲尔),人们会从中实现的接口类继承。 (理论上,在实践中可能无法正常工作那么好。)
还有一种叫做DRY原则-不重复自己。
在数据源的例子,你说有一些通用的代码,不同的实现之间的共同。 对我来说,似乎来处理,最好的办法是将有与它的通用代码和扩展它的一些具体类的抽象类。
其优点是,在通用的代码在每个bug修正有益于所有具体实现。
如果你去接口只,你将不得不保持其是自讨苦吃同一代码的多个副本。
关于抽象的+接口,如果它没有直接的理由,我不会去做。 从抽象类中提取接口是一个简单的重构,所以我会做它,只有当实际需要它。
请参阅下面的一般准则SE问题:
接口VS抽象类(一般OO)
实际使用情况的界面:
实施Strategy_pattern :定义你的战略,作为一个接口。 在运行时策略的具体实现的一个动态切换的实现。
定义多个不相关的类中的能力 。
实际使用情况的抽象类:
实施Template_method_pattern :定义一个算法的骨架。 子类不能改变algortihm的strucutre但他们可以重新定义子类中的实现的一部分。
当你想多个相关类与之间共享非静态和非最终变量“ 有一个 ”关系。
既abstradt类和接口的使用:
如果你想为一个抽象类,您可以将抽象方法的接口和抽象类可以简单地实现该接口。 抽象类的所有用例可以归入此类。