我正在阅读设计模式,并且读到原型设计模式消除了过多的子类化。
为什么子类化不好?使用原型会带来什么优于子类化的优势?
我正在阅读设计模式,并且读到原型设计模式消除了过多的子类化。
为什么子类化不好?使用原型会带来什么优于子类化的优势?
Answers:
为什么子类化太糟糕了
“太多”是一种判断。但是从我这里拿走是不好的。我使用的代码具有DEEP继承性,而且该代码简直难以阅读,理解,跟踪,跟踪,调试等。该代码实际上是不可能编写的。
原型模式消除了子类化
还是这个问题的意思是“放弃过多的子类化了吗?”。这种模式要求至少在那一点上克隆一个“模板”对象以避免子类化。没有规则说“模板”不能是子类。
偏重于继承而不是继承
这里的想法还包括委派和汇总。遵循这种启发式方法意味着您的软件趋向于更灵活,更易于维护,扩展和重用。
当类由部分组成时,可以在运行时替换这些部分。这对可测试性具有深远的影响。
测试更容易。您可以使用假零件(即“假装”,“双打”和其他测试用语)。我们代码的深层继承意味着我们必须实例化整个层次结构以对其进行任何测试。在我们的情况下,如果不在实际环境中运行代码,这是不可能的。例如,我们需要一个数据库来实例化业务对象。
变化会带来副作用和不确定性 -类别越“基础”,无论是好是坏,影响越广泛。由于副作用不确定,您可能不希望进行某些更改。否则对继承链中某个位置有利的更改对另一个不利。这当然是我的经验。
有两个原因。
是运行时性能。每次从超类调用子类时,您都在进行方法调用,因此,如果您嵌套了五个类并在基类中调用一个方法,则将进行五个方法调用。大多数编译器/运行时将尝试重新诊断并优化掉多余的调用,但是只有在非常简单的情况下才可以安全地这样做。
是您的程序员同伴的理智。如果您嵌套五个类,那么我必须检查所有四个父类,以确保您真的在基类中调用方法,这将变得很乏味。在调试程序时,我可能还必须逐步完成五个方法调用。
“太多”是一种判断。
与编程中的大多数事情一样,子类在合理的情况下并不是天生就不好。如果您的问题解决方案模型更适合作为层次结构而不是组成部分,则子类化可能是首选。
话虽如此,主张继承而不是继承是一个很好的经验法则。
子类化时,测试可能会更加困难(如radarbob所述)。在深层次结构中,隔离有问题的代码更加困难,因为实例化子类需要引入整个超类层次结构和一堆附加代码。使用组合方法,您可以使用单元测试,模拟对象等隔离和测试聚合对象的每个组件。
子类化还可能导致您暴露您可能不需要的实现细节。这使得难以控制对数据的基本表示的访问,并且使您与支持模型的特定实现联系在一起。
我能想到的一个示例是java.util.Properties,它继承自Hashtable。Properties类仅用于存储String-String对(这在Javadocs中有所说明)。由于继承的缘故,Hashtable的put和putAll方法已向Properties的用户公开。尽管存储属性的“正确”方法是使用setProperty(),但绝对没有阻止用户调用put()并传入String和Object的方法。
基本上,由于继承,属性的语义定义不明确。此外,如果有人想更改Properties的后备对象,则与使用Properties组合方法相比,对使用Properties的代码的影响将更大。
继承在某些情况下会破坏封装,如果确实发生,那就不好了。阅读更多。
在过去没有继承的过去,图书馆会发布API和使用它的应用程序来利用公开可见的内容,而图书馆现在拥有自己的方式来处理不断变化的内部机制而不会破坏App。
随着需求的发展,图书馆可以发展并拥有更多的客户。或者它可以通过从自己的类继承其他样式来提供扩展功能。到目前为止,一切都很好。
但是,最根本的是,如果一个应用程序继承了该类并开始对其进行子类化,那么现在一个子类实际上是一个客户而不是内部合作伙伴。但是,与明确定义公共API的明确方式不同,子类现在在库内部更深(访问所有私有变量等)。还算不错,但是讨厌的角色可以桥接API,而该API在APP以及库中太多了,
本质上,虽然并非总是如此,但是,
很容易滥用继承来破坏封装
如果这样的话,允许子类化可能是错误的。