java 合成 继承,关于Java:偏好合成与继承

本问题已经有最佳答案,请猛点这里访问。

Favor composition over inheritance

是非常流行的短语。我读了几篇文章,最后每篇文章都说

use inheritance when there is pure IS-A relationship between classes.

本文的一个示例:

苹果和水果之间存在着明显的"是"关系,即苹果是一种水果,但作者也将其表示为"苹果有"——一种水果(成分),用继承来实现时会显示出陷阱。

我在这里有些困惑,陈述的意思是什么

use inheritance when there is pure IS-A relationship between classes.

在继承上使用组合是否意味着即使存在纯IS-A关系,也要始终尝试应用组合,并且只在组合没有意义的情况下保留继承?

为什么java标签?

当您使用继承重用来自超类的代码,而不是重写方法和定义另一个多态行为时,通常会指示您应该使用组合而不是继承。

java.util.Properties类是继承使用不当的一个很好的例子。它不是使用哈希表来存储其属性,而是扩展哈希表,以便重用其方法,并避免使用委托重新实现其中的一些方法。

我反对,因为这是一个不涉及汽车、动物或水果的真实例子。然而,如果说明扩展HashTable的java.util.Properties是如何对设计产生负面影响的,这将是一个更有力的论据。我考虑过里斯科夫替代原理,我认为这不是问题。从理论上讲,由于性能/内存的原因,能够更改存储(哈希)机制可能很有用,但这在继承和组合中是不可能的。

非重复性问题:是否不建议编写一个包含所有子类都具有完美意义的方法的基类(如果是抽象的则更好),而不重写任何基类的方法?扩展HashTable的Properties不是一个很好的例子,因为Properties不应该关心整个HashTable特定的逻辑,只需要其中的一小部分,所以它不应该扩展HashTable,因为它不是一个,它只是使用一个?

我认为这是面向对象设计中讨论最多的一点。正如本文所建议的,组合总是优先于继承。这并不意味着你不应该使用继承。你应该去更有意义的地方(有争议的地方)。

使用合成有很多优点,其中有两个优点:

您将完全控制您的实现。也就是说,您只能公开您打算公开的方法。

超级类中的任何更改都可以通过只在类中修改来屏蔽。任何使用类的客户机类都不需要进行修改。

允许您控制何时加载超级类(延迟加载)

我的问题是,我不介意转向更多的组合,但是对于具有许多方法的类,在每个派生类中重复这个样板文件可能会很痛苦。当然,大多数类应该只有几个方法,但在某些情况下(例如,GUI窗口基类),您会忍不住拥有很多方法。

我想一个好的指导方针是:

When there is an IS-A relationship, use inheritance. Otherwise, use

composition.

这与面向对象设计中的另一个概念——多态性有关。多态性是许多OOP语言的一个特性,只要第一个类是第二个类的子类,就可以用一个对象代替另一个对象。

举例来说,想象一下,如果你有一个功能,接受一种动物。使用继承时,只有一个函数:

void feed( Animal a );

多态性保证了我们放入的动物的任何亚类都将被接受。否则,我们将被迫为每种类型编写一个函数。我认为这样做的好处大于它的缺点(例如减少封装)。

如果没有IS-A关系,我认为多态性不会非常有效。因此,最好使用组合并增强类之间的封装/隔离。

If there is no IS-A relationship, I think polymorphism won't be very effective. It would thus be better to use composition and have enhanced encapsulation/isolation between classes.1+1

另外,我想补充一点,装饰器模式是一个示例,您可以在继承上使用组合,并动态地向对象添加职责。在"有效继承比继承"项目中,在有效Java中提到了装饰器模式的例子。从Java API中获取一个例子;Buffer阅读器装入阅读器(而不是扩展FieleRader、PiPadReader、FieldReader等),因此有能力对任何类型的阅读器进行装饰。缓冲功能在运行时附加到这些读卡器上,这就是装饰器模式。

在这里,通过子类化进行扩展是不切实际的。

在本文中,没有这样的短语:

use inheritance when there is pure IS-A relationship between classes

此外,除了你的帖子,谷歌在其他地方没有找到它。

相反,文章写道:

Make sure inheritance models the is-a relationship.

My main guiding philosophy is that inheritance should be used only when a subclass is-a superclass. In the example above, an Apple likely is-a Fruit, so I would be inclined to use inheritance.

这意味着,如果存在关系,请首先尝试使用继承,而不是组合。而且,using composition over inheritance没有任何偏好——每个都有利于自己的角色。

each is good for its own role.1+1。我认为这意味着这取决于我们建立阶级关系的"动机"。如果它是"仅"用于代码重用,那么Favor composition over inheritance是有效的;如果其动机是模拟类之间实际存在的"实际关系",那么继承和组合都有自己的角色。如果存在纯粹的IS,我们可以选择继承——一种关系"尽管"事实上继承比组合有更多的问题,比如强耦合,否则选择组合。我说的对吗?

代码重用是一个强大的动机,仅仅选择继承就足够了。在许多情况下,强耦合被认为是有利的,而不是问题。在许多语言(Java)中,继承比作文更容易。只有经验才能让你感觉到什么是正确的方法,对于特定的情况,没有严格的规则。

当关系是永久的时使用继承。不要仅仅为了获得自由行为而使用扩展。这就是他们在IS上所指的——一个例子。只有当扩展类确实是父类的扩展时才进行扩展。有时它不会被切割和干燥,但一般来说。如果您需要从"正确的"类进行扩展,那么组合在将来也提供了灵活性。

这是一篇关于延伸的古老而伟大的文章:

http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html

我会说不,在水果/苹果的场景中,使用继承是很有意义的。这篇文章的作者也证实了这一点:"在上面的例子中,苹果很可能是一种水果,所以我倾向于使用继承。"

如果您的子类显然是一个超类,那么继承就可以了。在实践中,你会发现更多的情况下,更好地解决使用组合。

"如果你的子类显然是超类"?

@SimonNickerson"如果显然是一个"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值