何时使用接口或抽象类?何时使用?

Bli*_*ixt 33 oop abstract-class interface

虽然某些指导原则指出,当你想为继承不是明确的类定义合同时应该使用接口(IDomesticated),当类是另一个(Cat : Mammal,Snake : Reptile)的扩展时继承,有些情况(在我看来)这些准则进入灰色地带.

例如,说我的实施是Cat : Pet.Pet是一个抽象类.应该说是扩大到Cat : Mammal, IDomesticated那里Mammal是一个抽象类,IDomesticated是接口?或者我是否与KISS/YAGNI原则相冲突(尽管我不确定Wolf将来是否会有一个课程,但是无法继承Pet)?

远离隐喻Cats和Pets,假设我有一些表示传入数据源的类.他们都需要以某种方式实现相同的基础.我可以在抽象Source类中实现一些通用代码并从中继承.我也可以创建一个ISource接口(对我来说感觉更"正确")并在每个类中重新实现通用代码(这不太直观).最后,通过制作抽象类和界面,我可以"吃蛋糕并吃掉它".什么是最好的?

这两种情况提出了仅使用抽象类,只使用接口并同时使用抽象类和接口的要点.这些都是有效的选择,还是存在"规则",以便何时应该使用另一个?


我想通过"同时使用抽象类和接口"来澄清,当它们基本上表示相同的事物(Source并且ISource两者都具有相同的成员)时,包括这种情况,但是类在接口指定合同时添加了通用功能.

另外值得注意的是,这个问题主要针对不支持多重继承的语言(例如.NET和Java).

Mar*_*ann 36

作为第一个经验法则,我更喜欢基于.NET设计指南的接口上的抽象类.这种推理比.NET更广泛,但在" 框架设计指南"一书中有更好的解释.

优化抽象基类背后的主要原因是版本控制,因为您始终可以在不破坏现有客户端的情况下将新虚拟成员添加到抽象基类.这对接口来说是不可能的.

在某些情况下,接口仍然是正确的选择(特别是当您不关心版本控制时),但了解优缺点可以使您做出正确的决策.

所以在我继续之前作为部分答案:如果您决定首先对接口进行编码,那么只有接口和基类才有意义.如果允许接口,则必须仅针对该接口进行编码,否则您将违反Liskov替换原则.换句话说,即使您提供了实现接口的基类,也不能让您的代码使用该基类.

如果你决定对基类进行编码,那么拥有一个接口是没有意义的.

如果您决定对接口进行编码,则具有提供默认功能的基类是可选的.没有必要,但可能会加速实施者的工作,所以你可以提供一个礼貌.

想到的一个例子是ASP.NET MVC.请求管道在IController上工作,但是您通常使用Controller基类来实现行为.

最后的答案:如果使用抽象基类,只使用它.如果使用接口,基类是实现者的可选礼貌.


更新:不再喜欢接口上的抽象类,我已经很久没有了; 相反,我赞成使用SOLID作为指导的组合而不是继承.

(虽然我可以直接编辑上面的文字,但它会从根本上改变帖子的性质,因为有些人发现它有价值而不能投票,我宁愿让原文站起来,而是添加这个注意.帖子的后半部分仍然有意义,所以删除它也是一种耻辱.)

  • 定义一个接口和一个实现它的抽象类.然后,大多数实现只能扩展抽象类而不会出现版本问题(可以将新方法添加到接口和抽象类中),而如果这不可能(例如,当已经存在另一个超级)时,实现可以只实现接口. (2认同)

kyo*_*ryu 20

我倾向于使用基类(抽象或不抽象)来描述什么什么,而我使用接口来描述对象的功能.

哺乳动物,但它的一个功能是它是Pettable.

或者,换句话说,类是名词,而接口映射更接近形容词.


小智 12

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

  • 如果您预计要创建组件的多个版本,请创建一个抽象类.抽象类提供了一种简单易用的组件版本.通过更新基类,所有继承类都会随更改自动更新.另一方面,接口一旦创建就无法更改.如果需要新版本的接口,则必须创建一个全新的接口.

  • 如果您正在创建的功能在各种不同的对象中都有用,请使用界面.抽象类应主要用于密切相关的对象,而接口最适合为不相关的类提供通用功能.

  • 如果您正在设计小巧,简洁的功能,请使用接口.如果要设计大型功能单元,请使用抽象类.

  • 如果要在组件的所有实现中提供通用的实现功能,请使用抽象类.抽象类允许您部分实现您的类,而接口不包含任何成员的实现.