写点什么

设计模式:里氏替代原理(LSP)

作者:flow
  • 2022 年 8 月 05 日
  • 本文字数:1516 字

    阅读完需:约 5 分钟

作为一名 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 void addElement(Integer i) {    list.add(i);}
public Integer getElement(Integer index) { return list.get(index);}
复制代码


}


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 {


public static void main(String args[]) {    MyOrderedCollection collection1 = new MyOrderedCollection();    MyOrderedCollection collection2 = new MyOrderedAndSortedCollection();    int a = 8, b = 4;    collection1.addElement(a);    collection1.addElement(b);    collection2.addElement(a);    collection2.addElement(b);    getAndPrintSecondElement(collection1);    getAndPrintSecondElement(collection2);}
public static void getAndPrintSecondElement(MyOrderedCollection collection) { System.out.println("The second element is :" + collection.getElement(1));}
复制代码


}此代码的结果是:


第二个元素是 :4 第二个元素是 :8


为什么这是一个问题?


MyOrderEdAndSortedCollection 是有序的,所以从 MyOrderedCollection 派生出来似乎是一个好主意。但是由于这两个类不使用相同的顺序,因此可能会导致大问题:


MyOrderedCollection 使用广告订单排序 MyOrderedAndSortedCollection 使用自然排序假设 devA 编写并使用 MyOrderedCollection。两年后,devB 从 MyOrderedCollection 创建了 MyOrderedAndSortedCollection,因为他需要一个排序的集合。由于它是一个继承,因此使用 MyOrderedCollection 作为参数的函数也可以使用 MyOrderedAndSortedCollection。但是,如果其中一些函数使用 MyOrderedCollection 的特定排序呢?为了避免这种情况,devB 应该查看使用 MyOrderedCollection 的完整遗留代码,并修改遗留代码以检查引用是否为 MyOrderedAndSortedCollection 的实例。根据遗留代码的大小/复杂性,这可能需要数周时间,修改现有(和工作)代码可能不是一个好主意。


下面是一个遵循 LSP 的可能解决方案:


public interface MyCollection {


abstract public void addElement(Integer i);
abstract public Integer getElement(Integer index);
复制代码


}


public class MyOrderedCollection implements MyCollection {...}


public class MyOrderedAndSortedCollection implements MyCollection {...}使用此配置,MyOrderedCollection 和 MyOrderedAndSortedCollection 并不相同(即使它们共享相同的接口):


显式使用 MyOrderedCollection 的代码使用其排序,并且不能使用 MyOrderedAndSortedCollection 进行更改。使用 MyCollection 的代码不关心排序,因此它可以使用 MyOrderedCollection 还是 MyOrderedAndSortedCollection。这种模式可以看作是一个强大的行为子类型。

发布于: 刚刚阅读数: 4
用户头像

flow

关注

还未添加个人签名 2022.07.13 加入

还未添加个人简介

评论

发布
暂无评论
设计模式:里氏替代原理(LSP)_签约计划第三季_flow_InfoQ写作社区