设计模式:里氏替代原理(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()”而不修改

作为一名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 的继承示例:

publicclassMyOrderedCollection {

    protectedList<Integer> list = newArrayList<>();

 

    publicvoidaddElement(Integer i) {

        list.add(i);

    }

 

    publicInteger getElement(Integer index) {

        returnlist.get(index);

    }

}

 

publicclassMyOrderedAndSortedCollection extendsMyOrderedCollection {

    //overriding addElement so that the collection is sorted

    publicvoidaddElement(Integer i) {

        super.addElement(i);

        Collections.sort(super.list);

    }

}

 

publicclassExampleLSP1 {

 

    publicstaticvoidmain(String args[]) {

        MyOrderedCollection collection1 = newMyOrderedCollection();

        MyOrderedCollection collection2 = newMyOrderedAndSortedCollection();

        inta = 8, b = 4;

        collection1.addElement(a);

        collection1.addElement(b);

        collection2.addElement(a);

        collection2.addElement(b);

        getAndPrintSecondElement(collection1);

        getAndPrintSecondElement(collection2);

    }

 

    publicstaticvoidgetAndPrintSecondElement(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 的可能解决方案:

publicinterfaceMyCollection {

 

    abstractpublicvoidaddElement(Integer i);

 

    abstractpublicInteger getElement(Integer index);

}

 

publicclassMyOrderedCollection implementsMyCollection {

...

}

 

publicclassMyOrderedAndSortedCollection implementsMyCollection {

...

}

使用此配置,MyOrderedCollection 和 MyOrderedAndSortedCollection 并不相同(即使它们共享相同的接口):

  • 显式使用 MyOrderedCollection 的代码使用其排序,并且不能使用 MyOrderedAndSortedCollection 进行更改。
  • 使用 MyCollection 的代码不关心排序,因此它可以使用 MyOrderedCollection 还是 MyOrderedAndSortedCollection。

这种模式可以看作是一个强大的行为子类型

目录
相关文章
|
25天前
|
设计模式 安全 Java
【分布式技术专题】「Tomcat技术专题」 探索Tomcat技术架构设计模式的奥秘(Server和Service组件原理分析)
【分布式技术专题】「Tomcat技术专题」 探索Tomcat技术架构设计模式的奥秘(Server和Service组件原理分析)
29 0
|
6月前
|
设计模式 存储 Java
【设计模式——学习笔记】23种设计模式——备忘录模式Memento(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——备忘录模式Memento(原理讲解+应用场景介绍+案例介绍+Java代码实现)
53 0
|
6月前
|
设计模式 缓存 Java
【设计模式——学习笔记】23种设计模式——建造者模式Builder(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——建造者模式Builder(原理讲解+应用场景介绍+案例介绍+Java代码实现)
53 0
|
6月前
|
设计模式 存储 Java
【设计模式——学习笔记】23种设计模式——迭代器模式Iterator(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——迭代器模式Iterator(原理讲解+应用场景介绍+案例介绍+Java代码实现)
28 0
|
6月前
|
设计模式 Java 关系型数据库
【设计模式——学习笔记】23种设计模式——适配器模式Adapter(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——适配器模式Adapter(原理讲解+应用场景介绍+案例介绍+Java代码实现)
45 0
|
6月前
|
设计模式 存储 Java
【设计模式——学习笔记】23种设计模式——享元模式Flyweight(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——享元模式Flyweight(原理讲解+应用场景介绍+案例介绍+Java代码实现)
29 0
|
6月前
|
设计模式 Java 数据库连接
【设计模式——学习笔记】23种设计模式——外观模式Facade(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——外观模式Facade(原理讲解+应用场景介绍+案例介绍+Java代码实现)
48 0
|
6月前
|
设计模式 Java 应用服务中间件
【设计模式——学习笔记】23种设计模式——职责链/责任链模式(Chain of Responsibility)(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——职责链/责任链模式(Chain of Responsibility)(原理讲解+应用场景介绍+案例介绍+Java代码实现)
77 0
|
6月前
|
设计模式 算法 Java
【设计模式——学习笔记】23种设计模式——策略模式Strategy(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——策略模式Strategy(原理讲解+应用场景介绍+案例介绍+Java代码实现)
57 0
|
6月前
|
设计模式 Java 开发者
【设计模式——学习笔记】23种设计模式——状态模式State(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——状态模式State(原理讲解+应用场景介绍+案例介绍+Java代码实现)
44 0