为什么更喜欢组合而不是继承?每种方法都有哪些权衡?什么时候应该选择继承而不是组合?


当前回答

正如许多人所说的,我首先要检查是否存在“是”的关系。如果存在,我通常检查以下内容:

是否可以实例化基类。也就是说,基类是否可以是非抽象的。如果可以是非抽象的,我通常更喜欢写作

例如1。会计是员工。但我不会使用继承,因为Employee对象可以实例化。

例如2。书籍是SellingItem。SellingItem无法实例化-它是抽象概念。因此,我将使用遗传痤疮。SellingItem是一个抽象基类(或C#中的接口)

你觉得这种方法怎么样?

此外,我支持为什么要使用继承?

使用继承的主要原因不是作为组合的一种形式,而是为了让您可以获得多态行为。如果不需要多态性,那么可能不应该使用继承。

@马修。在https://softwareengineering.stackexchange.com/questions/12439/code-smell-inheritance-abuse/12448#comment303759_12448

继承的问题在于它可以用于两个正交的目的:接口(用于多态性)实现(用于代码重用)

参考

哪个班级设计更好?继承与聚合

其他回答

当你在两个类之间有一个is-a关系(例如狗是狗),你就去继承。

另一方面,当你在两个班级(学生有课程)或(老师学习课程)之间有一种或某种形容词关系时,你选择了作文。

合成与继承是一个广泛的主题。对于什么更好,没有真正的答案,因为我认为这一切都取决于系统的设计。

通常,对象之间的关系类型为选择其中一个对象提供了更好的信息。

如果关系类型是“is-A”关系,则继承是更好的方法。否则关系类型为“HAS-A”关系,则组合将更接近。

这完全取决于实体关系。

尽管作文是首选,但我想强调继承的优点和作文的缺点。

继承优势:

它建立了逻辑“IS a”关系。如果汽车和卡车是两种类型的车辆(基类),则子类是一个基类。即汽车就是车辆卡车是一种车辆通过继承,您可以定义/修改/扩展功能基类不提供实现,子类必须重写完整方法(抽象)=>您可以实现合约基类提供默认实现,子类可以更改行为=>您可以重新定义合约子类通过调用super.methodName()作为第一条语句来向基类实现添加扩展=>您可以扩展合约基类定义了算法的结构,子类将覆盖算法的一部分=>您可以在不改变基类骨架的情况下实现Template_method

组成的缺点:

在继承中,子类可以直接调用基类方法,即使它由于IS A关系而没有实现基类方法。如果使用组合,则必须在容器类中添加方法以公开包含的类API

例如,如果汽车包含车辆,并且您必须获得汽车的价格(已在车辆中定义),您的代码将如下

class Vehicle{
     protected double getPrice(){
          // return price
     }
} 

class Car{
     Vehicle vehicle;
     protected double getPrice(){
          return vehicle.getPrice();
     }
} 

将遏制视为一种关系。汽车“有”发动机,人“有”名字等等。

把继承看作是一种关系。汽车“是”车辆,人“是”哺乳动物等。

我不认为这种做法值得赞扬。我直接从史蒂夫·麦康奈尔(Steve McConnell)的《代码大全》第二版第6.3节中得到了答案。

我听过的一条经验法则是,当它是一种“is-A”关系时,应该使用继承;当它是“has-A”关系的时候,应该使用组合。尽管如此,我觉得你应该始终倾向于构图,因为它消除了很多复杂性。