里氏替换原则 http://en.wikipedia.org/wiki/Liskov_substitution_principle是原则之一SOLID http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29。我现在已经多次阅读这个原则并试图理解它。
这是我从中得到的,
这一原则与人们之间强有力的行为契约有关。
类的层次结构。子类型应该能够替换为
超类型而不违反合同。
我读过一些其他的articles http://www.objectmentor.com/resources/articles/lsp.pdf我也是,对这个问题的思考有点迷失。做Collections.unmodifiableXXX()
方法不违反LSP?
上面链接的文章摘录:
换句话说,当通过其基类接口使用对象时,
用户只知道基础的前提条件和后置条件
班级。因此,派生对象不能期望此类用户遵守
比基类所需的前提条件更强的前提条件
为什么我这么认为?
Before
class SomeClass{
public List<Integer> list(){
return new ArrayList<Integer>(); //this is dumb but works
}
}
After
class SomeClass{
public List<Integer> list(){
return Collections.unmodifiableList(new ArrayList<Integer>()); //change in implementation
}
}
我无法改变的实施SomeClass
返回将来不可修改的列表。编译将起作用,但如果客户端尝试以某种方式改变List
返回然后它会在运行时失败。
这就是 Guava 创建单独的原因吗?不可变XXX https://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained集合接口?
这不是直接违反LSP还是我完全搞错了?
LSP 表示每个子类都必须遵守与超类相同的契约。无论情况是否如此Collections.unmodifiableXXX()
因此取决于本合同如何解读。
返回的对象Collections.unmodifiableXXX()
如果尝试对它们调用任何修改方法,则会抛出异常。例如,如果add()
被称为,一个UnsupportedOperationException
会被抛出。
什么是总承包合同add()
?根据API文档 http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Collection.html#add%28E%29 it is:
确保此集合包含指定的元素(可选
手术)。如果此集合由于以下原因而发生更改,则返回 true
称呼。 (如果该集合不允许重复,则返回 false
已包含指定元素。)
如果这是完整的合同,那么确实不能在所有可以使用集合的地方使用不可修改的变体。然而,该规范继续说道:
如果集合出于任何原因拒绝添加特定元素
除了它已经包含该元素之外,它还必须抛出一个
异常(而不是返回 false)。这保留了不变性
集合始终包含在此之后的指定元素
呼叫返回。
这明确允许实现具有不添加参数的代码add
到集合,但会导致异常。当然,这包括收藏品客户有义务考虑这种(合法)可能性。
因此,行为子类型(或 LSP)仍然得到满足。
但这表明,如果计划在子类中具有不同的行为,则也必须在顶级类的规范中预见到。
顺便说一句,好问题。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)