关于如何在面向对象系统中最好地扩展、增强和重用代码,有两种思想流派:
继承:通过创建子类来扩展类的功能。重写子类中的超类成员以提供新功能。使方法抽象/虚拟,以便在超类需要特定接口但对其实现不可知时,强制子类“填充空白”。
聚合:通过将其他类合并到一个新类中来创建新功能。为这个新类附加一个公共接口,以便与其他代码进行互操作。
它们的好处、成本和后果是什么?还有其他选择吗?
我看到这场辩论定期举行,但我认为没有人要求它
堆栈溢出(尽管有一些相关的讨论)。谷歌也出人意料地缺乏好的搜索结果。
Tags:
这种差异通常表示为“是a”和“有a”之间的差异。继承,即“is a”关系,在Liskov Substitution Principle中得到了很好的总结。聚合,即“has a”关系,只是-它表明聚合对象具有其中一个聚合对象。
进一步存在区别:C++中的私有继承表示“以关系”实现,也可以通过(非暴露)成员对象的聚合来建模。
在GOF开始时,它们声明
这将进一步讨论here
这不是什么是最好的,而是什么时候用什么。
在“正常”情况下,一个简单的问题就足以找出我们是否需要继承或聚合。
但是,有一个很大的灰色区域。所以我们需要几个其他的技巧。
缩短时间。如果没有使用接口的一部分,或者必须更改接口以避免出现不合逻辑的情况,我们应该使用聚合。我们只需要使用继承,如果我们需要几乎所有的功能而没有重大的更改。当有疑问时,使用聚合。
另一种可能性是,如果我们有一个类需要原始类的一部分功能,则将原始类拆分为一个根类和一个子类。并让新类从根类继承。但你应该小心,不要造成不合逻辑的分离。
让我们添加一个示例。我们有一个“狗”类的方法:“吃”、“走”、“叫”、“玩”。
我们现在需要一个“猫”类,它需要“吃”、“走”、“咕噜”和“玩”。所以首先试着把它从狗身上伸出来。
看,好吧,等一下。这只猫会叫(爱猫的人会因此杀了我)。一只吠叫的猫违反了宇宙的法则。所以我们需要重写Bark方法,这样它什么也做不了。
好吧,这行,但闻起来很难闻。因此,让我们尝试聚合:
好的,这很好。这只猫不再叫了,甚至不再沉默。但它还是有一只内在的狗想要离开。所以让我们试试第三种解决方案:
这要干净得多。没有内部狗。猫和狗在同一水平。我们甚至可以引进其他宠物来扩展这个模型。除非是一条鱼,或是什么不能走路的东西。在这种情况下,我们再次需要重构。但那是另一次。
相关问题 更多 >
编程相关推荐