作为一名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 的继承示例:
|
此代码的结果是:
第二个元素是 :4
第二个元素是 :8
为什么这是一个问题?
MyOrderEdAndSortedCollection是有序的,所以从MyOrderedCollection派生出来似乎是一个好主意。但是由于这两个类不使用相同的顺序,因此可能会导致大问题:
- MyOrderedCollection 使用广告订单排序
- MyOrderedAndSortedCollection 使用自然排序
假设 devA 编写并使用 MyOrderedCollection。两年后,devB 从 MyOrderedCollection 创建了 MyOrderedAndSortedCollection,因为他需要一个排序的集合。由于它是一个继承,因此使用 MyOrderedCollection 作为参数的函数也可以使用 MyOrderedAndSortedCollection。但是,如果其中一些函数使用MyOrderedCollection的特定排序呢?
为了避免这种情况,devB 应该查看使用 MyOrderedCollection 的完整遗留代码,并修改遗留代码以检查引用是否为 MyOrderedAndSortedCollection 的实例。根据遗留代码的大小/复杂性,这可能需要数周时间,修改现有(和工作)代码可能不是一个好主意。
下面是一个遵循 LSP 的可能解决方案:
|
使用此配置,MyOrderedCollection 和 MyOrderedAndSortedCollection 并不相同(即使它们共享相同的接口):
- 显式使用 MyOrderedCollection 的代码使用其排序,并且不能使用 MyOrderedAndSortedCollection 进行更改。
- 使用 MyCollection 的代码不关心排序,因此它可以使用 MyOrderedCollection 还是 MyOrderedAndSortedCollection。
这种模式可以看作是一个强大的行为子类型。