组合和继承是一样的吗? 如果我想实现组合模式,我如何在Java中做到这一点?


当前回答

@Michael Rodrigues给出的答案不正确(我道歉;我不能直接评论),这可能会导致一些混乱。

接口实现是一种继承形式…当你实现一个接口时,你不仅继承了所有的常量,你还将你的对象提交为接口指定的类型;这仍然是一种“是”的关系。如果汽车实现了Fillable,那么汽车“是-a”Fillable,并且可以在任何需要使用Fillable的代码中使用。

组合从根本上不同于继承。当您使用组合时,您(如其他回答所示)在两个对象之间建立了“has-a”关系,而不是使用继承时所建立的“is-a”关系。

所以,从其他问题中关于汽车的例子来看,如果我想说一辆汽车“有一个”油箱,我会使用如下的组合:

public class Car {

private GasTank myCarsGasTank;

}

希望这能消除任何误解。

其他回答

另一个例子,考虑一个汽车类,这将是一个很好的组合使用,一个汽车将“有”一个发动机,一个变速器,轮胎,座位,等等。它不会扩展任何这些类。

复合意味着创建一个与特定类有关系的类的对象。 假设学生与会计有关系;

继承是,这是带有扩展特性的前一个类。这意味着这个新类是具有一些扩展特性的旧类。 假设学生是学生,但所有的学生都是人。所以这是学生和人类之间的关系。这就是继承。

它们完全不同。继承是一种“是-是”关系。作文是“has-a”。

通过使用另一个类C的实例作为类的字段来进行组合,而不是扩展C。java.util就是一个很好的例子,其中组合比继承要好得多。堆栈,它目前扩展了java.util.Vector。现在看来,这是一个大错。堆栈“is-NOT-a”向量;不应该允许任意插入和删除元素。应该是合成。

不幸的是,现在纠正这个设计错误已经太晚了,因为现在更改继承层次结构将破坏与现有代码的兼容性。如果Stack使用组合而不是继承,那么它总是可以被修改为使用另一种数据结构,而不会违反API。

我强烈推荐Josh Bloch的《Effective Java第二版》

项目16:比起继承,更喜欢组合 项目17:设计和文件的继承或禁止

好的面向对象设计不是随意扩展现有的类。你的第一直觉应该是作曲。


参见:

组合与继承:两种基本的类关联方法的比较

合成就像它听起来一样-你通过插入部分来创建一个对象。

这个答案的其余部分错误地基于以下前提。 这是通过接口完成的。 例如,使用上面的Car例子,

Car implements iDrivable, iUsesFuel, iProtectsOccupants
Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
House implements iProtectsOccupants
Generator implements iUsesFuel

用一些标准的理论组件,你就可以构建你的对象。然后,你的工作就是填写房子如何保护它的居住者,以及汽车如何保护它的居住者。

继承则正好相反。您从一个完整(或半完整)对象开始,然后替换或覆盖您想要更改的各种位。

例如,机动车辆可能带有可燃料方法和驱动方法。您可以保留Fuel方法,因为给摩托车和汽车加油是一样的,但您可以重写Drive方法,因为摩托车的运行方式与汽车非常不同。

通过继承,一些类已经完全实现,而其他类的方法必须重写。在合成中什么都没有给你。(但是你可以通过调用其他类中的方法来实现接口,如果你碰巧有一些东西的话)。

组合被认为是更灵活的,因为如果你有一个像iUsesFuel这样的方法,你可以在其他地方有一个方法(另一个类,另一个项目),它只关心处理可以被燃料的对象,不管它是汽车、船、炉子、烧烤等等。接口要求那些声称实现了该接口的类实际上拥有该接口的全部方法。例如,

iFuelable Interface:
   void AddSomeFuel()
   void UseSomeFuel()
   int  percentageFull()

然后你可以在其他地方有一个方法

private void FillHerUp(iFuelable : objectToFill) {

   Do while (objectToFill.percentageFull() <= 100)  {

        objectToFill.AddSomeFuel();
   }

奇怪的例子,但它表明这个方法并不关心它在填充什么,因为对象实现了iUsesFuel,它可以被填充。故事结束了。

如果你使用继承,你将需要不同的FillHerUp方法来处理机动车辆和烧烤,除非你有一些相当奇怪的“ObjectThatUsesFuel”基础对象来继承。

不,两者都不一样。组合遵循“HAS-A”关系,继承遵循“IS-A”关系。组合的最佳例子是战略模式。