设计模式:里氏替代原理(LSP)
作为一名 Java 开发人员,我从未听说过 LSP 模式。只有当我读到一些关于 C++的东西时,我才遇到了这种模式。这很奇怪,因为这种模式有时被视为面向对象编程的 5 个原则之一。
该原则由 Barbara Liskov 于 1987 年首次提出,并于 1994 年表述为:
“设 q(x) 是一个可证明 T 类型的对象 x 的属性。则 q(y) 对于 S 类型的对象 y 应该是可证明的,其中 S 是 T 的子类型。“
换句话说:
如果类 B 是类 A 的子类,如果 A 有一个方法 f(),如果 b 是 B 的实例和 A 的实例,那么在代码的所有部分使用“a.f()”应该能够使用“b.f()”而不修改代码的行为
让我们看一个不尊重 LSP 的继承示例:
public class MyOrderedCollection {protected List<Integer> list = new ArrayList<>();
}
public class MyOrderedAndSortedCollection extends MyOrderedCollection {//overriding addElement so that the collection is sortedpublic void addElement(Integer i) {super.addElement(i);Collections.sort(super.list);}}
public class ExampleLSP1 {
}此代码的结果是:
第二个元素是 :4 第二个元素是 :8
为什么这是一个问题?
MyOrderEdAndSortedCollection 是有序的,所以从 MyOrderedCollection 派生出来似乎是一个好主意。但是由于这两个类不使用相同的顺序,因此可能会导致大问题:
MyOrderedCollection 使用广告订单排序 MyOrderedAndSortedCollection 使用自然排序假设 devA 编写并使用 MyOrderedCollection。两年后,devB 从 MyOrderedCollection 创建了 MyOrderedAndSortedCollection,因为他需要一个排序的集合。由于它是一个继承,因此使用 MyOrderedCollection 作为参数的函数也可以使用 MyOrderedAndSortedCollection。但是,如果其中一些函数使用 MyOrderedCollection 的特定排序呢?为了避免这种情况,devB 应该查看使用 MyOrderedCollection 的完整遗留代码,并修改遗留代码以检查引用是否为 MyOrderedAndSortedCollection 的实例。根据遗留代码的大小/复杂性,这可能需要数周时间,修改现有(和工作)代码可能不是一个好主意。
下面是一个遵循 LSP 的可能解决方案:
public interface MyCollection {
}
public class MyOrderedCollection implements MyCollection {...}
public class MyOrderedAndSortedCollection implements MyCollection {...}使用此配置,MyOrderedCollection 和 MyOrderedAndSortedCollection 并不相同(即使它们共享相同的接口):
显式使用 MyOrderedCollection 的代码使用其排序,并且不能使用 MyOrderedAndSortedCollection 进行更改。使用 MyCollection 的代码不关心排序,因此它可以使用 MyOrderedCollection 还是 MyOrderedAndSortedCollection。这种模式可以看作是一个强大的行为子类型。
版权声明: 本文为 InfoQ 作者【flow】的原创文章。
原文链接:【http://xie.infoq.cn/article/10553d5c3edeb71608098752d】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论