设计模式:里氏替代原理(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。

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

目录
相关文章
|
8月前
|
设计模式 安全 Java
【分布式技术专题】「Tomcat技术专题」 探索Tomcat技术架构设计模式的奥秘(Server和Service组件原理分析)
【分布式技术专题】「Tomcat技术专题」 探索Tomcat技术架构设计模式的奥秘(Server和Service组件原理分析)
119 0
|
设计模式 存储 Java
【设计模式——学习笔记】23种设计模式——备忘录模式Memento(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——备忘录模式Memento(原理讲解+应用场景介绍+案例介绍+Java代码实现)
92 0
|
设计模式 存储 Java
【设计模式——学习笔记】23种设计模式——迭代器模式Iterator(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——迭代器模式Iterator(原理讲解+应用场景介绍+案例介绍+Java代码实现)
58 0
|
设计模式 存储 Java
【设计模式——学习笔记】23种设计模式——享元模式Flyweight(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——享元模式Flyweight(原理讲解+应用场景介绍+案例介绍+Java代码实现)
74 0
|
8月前
|
设计模式 消息中间件 Java
Java 设计模式:探索发布-订阅模式的原理与应用
【4月更文挑战第27天】发布-订阅模式是一种消息传递范式,被广泛用于构建松散耦合的系统。在 Java 中,这种模式允许多个对象监听和响应感兴趣的事件。
457 2
|
8月前
|
设计模式 算法 Java
Java 设计模式:深入模板方法模式的原理与应用
【4月更文挑战第27天】模板方法模式是一种行为设计模式,主要用于定义一个操作中的算法的框架,允许子类在不改变算法结构的情况下重定义算法的某些特定步骤。
78 1
|
设计模式 Java 数据库连接
【设计模式——学习笔记】23种设计模式——外观模式Facade(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——外观模式Facade(原理讲解+应用场景介绍+案例介绍+Java代码实现)
120 0
|
设计模式 Java 容器
【设计模式——学习笔记】23种设计模式——组合模式Composite(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——组合模式Composite(原理讲解+应用场景介绍+案例介绍+Java代码实现)
149 0
【设计模式——学习笔记】23种设计模式——组合模式Composite(原理讲解+应用场景介绍+案例介绍+Java代码实现)
|
设计模式 Java 应用服务中间件
【设计模式——学习笔记】23种设计模式——职责链/责任链模式(Chain of Responsibility)(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——职责链/责任链模式(Chain of Responsibility)(原理讲解+应用场景介绍+案例介绍+Java代码实现)
166 0

热门文章

最新文章

  • 1
    设计模式转型:从传统同步到Python协程异步编程的实践与思考
    64
  • 2
    C++一分钟之-设计模式:工厂模式与抽象工厂
    54
  • 3
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    61
  • 4
    C++一分钟之-C++中的设计模式:单例模式
    79
  • 5
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    47
  • 6
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    81
  • 7
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    70
  • 8
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    54
  • 9
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    63
  • 10
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    137