王争《设计模式之美》学习笔记Liskov Substitution Principle,缩写为 LSP ,描述:,今天小编就来说说关于多态的定义和功能?下面更多详细答案一起来看看吧!

多态的定义和功能(设计模式之美十五)

多态的定义和功能

王争《设计模式之美》学习笔记

如何理解“里式替换原则”?

Liskov Substitution Principle,缩写为 LSP ,描述:

子类对象(object of subtype/derived class)能够替换程序(program)中父类对象(object of base/parent class)出现的任何地方,并且保证原来程序的逻辑行为(behavior)不变及正确性不被破坏。

作者使用Transporter 类及其之类SecurityTransporter说明了多态和里式替换的不同

多态是面向对象编程的一大特性,也是面向对象编程语言的一种语法,而里式替换是一种设计原则,是用来指导继承关系中子类该如何设计的,子类的设计要保证在替换父类的时候,不改变原有程序的逻辑以及不破坏原有程序的正确性。

哪些代码明显违背了 LSP?

里式替换原则还有另外一个更加能落地、更有指导意义的描述,那就是“DesignBy Contract”,中文翻译就是“按照协议来设计”。

为了更好地理解这句话,我举几个违反里式替换原则的例子来解释一下。

1. 子类违背父类声明要实现的功能

父类中提供的 sortOrdersByAmount() 订单排序函数,是按照金额从小到大来给订单排序的,而子类重写这个 sortOrdersByAmount() 订单排序函数之后,是按照创建日期来给订单排序的。那子类的设计就违背里式替换原则。

2. 子类违背父类对输入、输出、异常的约定

在父类中,某个函数约定:运行出错的时候返回 null;获取数据为空的时候返回空集合 (empty collection)。而子类重载函数之后,实现变了,运行出错返回异常 (exception),获取不到数据返回 null。那子类的设计就违背里式替换原则。

3. 子类违背父类注释中所罗列的任何特殊说明

父类中定义的withdraw()提现函数的注释是这么写的:“用户的提现金额不得超过账户余额......”,而子类重写withdraw()函数之后,针对VIP账号实现了透支提现的功能,也就是提现金额可以大于账户余额,那这个子类的设计也是不符合里式替换原则的。

判断是否 违背里式替换原则的小窍门:

拿父类的单元测试去验证子类的代码。如果某些单元测试运行失败,就有可能说明,子类的设计实现没有完全地遵守父类的约定,子类有可能违背了里式替换原则。

重点回顾

里式替换原则是用来指导,继承关系中子类该如何设计的一个原则。理解里式替换原则,最核心的就是理解“design by contract,按照协议来设计”这几个字。父类定义了函数的“约定”(或者叫协议),那子类可以改变函数的内部实现逻辑,但不能改变函数原有的“约定”。这里的约定包括:函数声明要实现的功能;对输入、输出、异常的约定;甚至 包括注释中所罗列的任何特殊说明。

参考:https://time.geekbang.org/column/intro/250?code=gLit0LpsKZQ6vOVqS1htGOSAKYLCYeMuklw2dwajH-4=

,