简体   繁体   English

有效的Java:转发类的安全性

[英]Effective Java: Safety of Forwarding Classes

Effective Java 3rd Edition, Item 18: Favor composition over inheritance describes an issue with using inheritance to add behavior to a class: 有效的Java第3版,第18项:优先于继承的组合描述了使用继承向类添加行为的问题:

A related cause of fragility in subclasses is that their superclass can acquire new methods in subsequent releases. 子类中脆弱性的一个相关原因是它们的超类可以在后续版本中获取新方法。 Suppose a program depends for its security on the fact that all elements inserted into some collection satisfy some predicate. 假设程序依赖于其安全性,因为插入到某个集合中的所有元素都满足某些谓词。 This can be guaranteed by subclassing the collection and overriding each method capable of adding an element to ensure that the predicate is satisfied before adding the element. 这可以通过继承集合并覆盖每个能够添加元素的方法来保证,以确保在添加元素之前满足谓词。 This works fine until a new method capable of inserting an element is added to the superclass in a subsequent release. 这可以正常工作,直到在后续版本中将能够插入元素的新方法添加到超类中。 Once this happens, it becomes possible to add an "illegal" element merely by invoking the new method, which is not overridden in the subclass. 一旦发生这种情况,仅通过调用新方法就可以添加“非法”元素,而新方法不会在子类中重写。

The recommended solution: 推荐的解决方案:

Instead of extending an existing class, give your new class a private field that references an instance of the existing class... Each instance method in the new class invokes the corresponding method on the contained instance of the existing class and returns the results. 不要扩展现有类,而是为新类提供一个引用现有类实例的私有字段...新类中的每个实例方法都会在现有类的包含实例上调用相应的方法并返回结果。 This is known as forwarding , and the methods in the new class are known as forwarding methods ... adding new methods to the existing class will have no impact on the new class... It's tedious to write forwarding methods, but you have to write the reusable forwarding class for each interface only once, and forwarding classes may be provided for you. 这称为转发 ,新类中的方法称为转发方法 ...向现有类添加新方法对新类没有影响...编写转发方法很繁琐,但你必须为每个接口只写一次可重用转发类,并为您提供转发类。 For example, Guava provides forwarding classes for all of the collection interfaces. 例如,Guava为所有集合接口提供转发类。

My question is, doesn't the risk remain that methods could also be added to the forwarding class , thereby breaking the invariants of the subclass? 我的问题是,风险是否仍然存在方法也可以添加到转发类 ,从而打破子类的不变量? How could an external library like Guava ever incorporate newer methods in forwarding classes without risking the integrity of its clients? 像Guava这样的外部库如何在转发类时采用更新的方法而不会冒客户端的完整性?

The tacit assumption seems to be that you are the one writing the forwarding class, therefore you are in control of whether anything gets added to it. 默认的假设似乎是是编写转发类的人,因此你可以控制是否有任何东西被添加到它。 That's the common way of using composition over inheritance, anyway. 无论如何,这是使用组合而不是继承的常用方法。

The Guava example seems to refer to the Forwarding Decorators , which are explicitly designed to be inherited from. Guava示例似乎引用了Forwarding Decorators ,它明确地设计为继承自。 But they are just helpers to make it simpler to create these forwarding classes without having to define every method in the interface; 但它们只是帮助创建这些转发类更简单,而无需在接口中定义每个方法; they explicitly don't shield you from any methods being added in the future that you might need to override as well: 它们明确地不会保护您免受将来可能需要覆盖的任何方法的影响:

Remember, by default, all methods forward directly to the delegate, so overriding ForwardingMap.put will not change the behavior of ForwardingMap.putAll . 请记住,默认情况下,所有方法都直接转发给委托,因此重写ForwardingMap.put不会更改ForwardingMap.putAll的行为。 Be careful to override every method whose behavior must be changed, and make sure that your decorated collection satisfies its contract. 小心覆盖必须更改其行为的每个方法,并确保您的装饰集合满足其合同。

So, if I understood all this correctly, Guava is not such a great example. 所以,如果我理解这一切,番石榴就不是一个很好的例子。

doesn't the risk remain that methods could also be added to the forwarding class, thereby breaking the invariants of the subclass? 风险是否仍然存在方法也可以添加到转发类,从而打破子类的不变量?

Composition is an alternative to inheritance, so when you use composition, there is no sub-class. 组合是继承的替代方法,因此当您使用组合时,没有子类。 If you add new public methods to the forwarding class (which may access methods of the contained instance), that means you want these methods to be used. 如果向转发类添加新的公共方法(可以访问包含的实例的方法),则意味着您希望使用这些方法。

因为您是转发类的所有者,所以只有您可以向其添加新方法,从而保持不变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM