设计模式:里氏替换原则(LSP)[译文]

简介: 一篇关于里氏替换原则理解的文章。作者表达出了自己对原则的理解,并且举了具体的场景分析了里氏替换原则。我自己看完还是收获颇丰的。可能是因为我才疏学浅吧。

译文

作为一个Java开发者,我从没有听过LSP模式。我只在读一些C++相关的东西的时候听说过这种模式。这非常奇怪,因为这种模式有时候被当作面向对象编程的五大原则之一

这个原则是 Barbara Liskov于1987年第一次提出,并在1994年阐述为:

"假设S是T的子类型,t是T的对象,s是S的对象。如果q(t)能跑通,那么q(s)也应该能跑通。"

“Letq(x) be a property provable about objects x of type T. Then q(y) should be provable for objects y of type S,where S is a subtype of T.

换句话说:

  • 如果B是A的子类,
  • A有一个方法f(),
  • 如果b是B的实例,a是a的实例,
  • 那么在不修改代码行为的前提下,所有能调用"a.f()"的地方,也应该能够调用“b.f()”。

让我们看一个不遵守LSP原则的继承的例子。

publicclassMyOrderedCollection {
protectedList<Integer>list=newArrayList<>();
publicvoidaddElement(Integeri) {
list.add(i);
    }
publicIntegergetElement(Integerindex) {
returnlist.get(index);
    }
}
publicclassMyOrderedAndSortedCollectionextendsMyOrderedCollection {
// 重写 addElement将集合排序publicvoidaddElement(Integeri) {
super.addElement(i);
Collections.sort(super.list);
    }
}
publicclassExampleLSP1 {
publicstaticvoidmain(Stringargs[]) {
MyOrderedCollectioncollection1=newMyOrderedCollection();
MyOrderedCollectioncollection2=newMyOrderedAndSortedCollection();
inta=8, b=4;
collection1.addElement(a);
collection1.addElement(b);
collection2.addElement(a);
collection2.addElement(b);
getAndPrintSecondElement(collection1);
getAndPrintSecondElement(collection2);
    }
publicstaticvoidgetAndPrintSecondElement(MyOrderedCollectioncollection) {
System.out.println("The second element is :"+collection.getElement(1));
    }
}

代码的运行结果是:

The second element is :4
The second element is :8

这结果为什么是一个隐患

假设开发者A写了MyOrderedCollection。两年后的某一天,开发者B由于需要使用到排序后的集合,便令MyOrderedAndSortedCollection继承了MyOrderedCollection 。由于是继承关系,所以能够将MyOrderedCollection作为参数的函数,MyOrderedAndSortedCollection也能作为参数使用。当其中一些函数就是要用到MyOrderedCollection中的插入时顺序怎么办?

为了避免这种情况,开发者B需要检查所有使用了MyOrderedCollection的遗留代码,并且确认它们是否会引用到MyOrderedAndSortedCollection上。根据遗留代码的数量与复杂程度,这可能会花费好几周的时间。而且去动现存(在运行)的代码,并不是一件好事。

下列方式就是遵守LSP原则的一种可行方案:

publicinterfaceMyCollection {
abstractpublicvoidaddElement(Integeri);
abstractpublicIntegergetElement(Integerindex);
}
publicclassMyOrderedCollectionimplementsMyCollection {
...
}
publicclassMyOrderedAndSortedCollectionimplementsMyCollection {
...
}

通过这种配置方式,MyOrderedCollectionMyOrderedAndSortedCollection就不一样了(即使他们实现了同一个接口):

  • 一定要使用插入时顺序的代码就用MyOrderedCollection,它不会被MyOrderedAndSortedCollection修改掉
  • 一段使用了MyCollection的代码一定是不会受到插入顺序的影响的。所以它既可以是MyOrderedCollection也可以是MyOrderedAndSortedCollection

这种模式可以被视作一种强行为子类型

原文链接

链接:Design Pattern: Liskov’s Substitution Principle (LSP) | Coding Geek (coding-geek.com)

译者是个菜鸟,初学Java,翻译仅为了提高提高自身阅读英文技术贴的能力。如有错误还望指正。

侵删。


相关文章
|
10天前
|
设计模式
设计模式 六大原则之里氏替换原则
设计模式 六大原则之里氏替换原则
|
2月前
|
设计模式 Java 开发者
Java设计模式七大原则之里氏替换原则
Java设计模式七大原则之里氏替换原则
35 0
|
设计模式
设计模式(4) --里氏替换原则
设计模式(4) --里氏替换原则
设计模式(4) --里氏替换原则
|
设计模式
设计模式七大原则——里氏替换原则
设计模式七大原则——里氏替换原则
设计模式七大原则——里氏替换原则
|
设计模式
设计模式(六)之里氏替换原则
里氏替换原则,为继承定义规范。 里氏替换原则有如下特点:代码共享,减少创建类的工作量、提高代码的重用性、提高代码的可扩展性、提高产品代码的开放性、继承侵入性 只要继承,必须拥有父类的内容、降低代码的灵活性,子类必须拥有父类的属性和方法、增强耦合性。
183 0
设计模式(六)之里氏替换原则
|
设计模式 Java
【Java设计模式】如何正确的使用继承?里氏替换原则的使用
【Java设计模式】如何正确的使用继承?里氏替换原则的使用
【Java设计模式】如何正确的使用继承?里氏替换原则的使用
|
设计模式
【设计模式】软件设计七大原则 ( 里氏替换原则 | 定义 | 定义扩展 | 引申 | 意义 | 优点 )
【设计模式】软件设计七大原则 ( 里氏替换原则 | 定义 | 定义扩展 | 引申 | 意义 | 优点 )
178 0
|
设计模式
设计模式—— 二:里氏替换原则
设计模式—— 二:里氏替换原则
103 0
设计模式—— 二:里氏替换原则
|
设计模式 安全 Java
可能是最好的设计模式入门教程——里氏替换原则
可能是最好的设计模式入门教程——里氏替换原则
282 0
可能是最好的设计模式入门教程——里氏替换原则
|
设计模式
【设计模式】软件设计七大原则 ( 里氏替换原则 | 代码示例 | 类示例 | 方法入参示例 | 方法返回值示例 )(一)
【设计模式】软件设计七大原则 ( 里氏替换原则 | 代码示例 | 类示例 | 方法入参示例 | 方法返回值示例 )(一)
99 0