深入理解设计原则之里氏替换原则(LSP)

news/2024/11/8 17:51:16/

系列文章目录

C++高性能优化编程系列
深入理解设计原则系列
深入理解设计模式系列
高级C++并发线程编程

LSP:里氏替换原则

  • 系列文章目录
  • 1、里氏替换原则的定义和解读
  • 2、里氏替换原则可以用于哪些设计模式中?
  • 3、如何使用里氏替换原则来降低代码耦合度?
  • 4、违反里氏替换原则的反模式
  • 5、案例解读
  • 6、里氏替换原则与多态的区别
  • 7、小结

1、里氏替换原则的定义和解读

里氏替换原则(Liskov Substitution Principle, LSP)于1986年有Barbara Liskov提出,他当时是这样描述这条原则的:如果S是T的子类型,那么T的对象可以被S的对象所替换,并不影响代码的运行。1996年,Robert Martin在他的SOLID原则中重新描述了里氏替换原则:使用父类对象的函数可以在不了解子类的情况下替换为使用子类对象
结合上面的描述,我们将里氏替换原则描述为:子类对象能够替换到程序中的父类对象出现的任何地方,并且保证程序原有的逻辑行为不变和正确性不被破坏

2、里氏替换原则可以用于哪些设计模式中?

将里氏替换原则应用于设计模式中,它可以用在许多设计模式中,例如:

  1. 工厂模式:子类可以替换父类,而不会影响到工厂的实现。
  2. 策略模式:不同的策略可以被替换,而不会影响到程序的正确性。
  3. 装饰器模式:装饰器可以替换被装饰的对象,而不会破坏程序的可扩展性。
  4. 模板方法模式:子类可以被使用来扩展或修改模板方法,而不会影响到程序的正确性。

总之,里氏替换原则是一个通用的设计原则,可以在许多设计模式中使用,以增强程序的可读性、可维护性和可扩展性。

3、如何使用里氏替换原则来降低代码耦合度?

通过遵循里氏替换原则,可以使得代码更加灵活、可扩展、易维护。下面是几种具体的方法来降低代码耦合度:

  1. 使用接口而不是具体的类:对于一个类,尽可能使用其接口而非具体的实现。这样可以减少对具体实现的依赖,并且可以更容易地替换实现。
  2. 将通用的行为移到基类:将一些通用的方法或属性移动到基类中,这样子类就可以继承这些方法并添加自己的实现,而不是每个子类都去重复实现相同的方法。
  3. 使用抽象类或接口来表示通用行为:通过使用抽象类或接口来表示通用行为,可以使得代码更加灵活和可扩展。当需要添加新的特定行为时,只需要实现新的抽象类或接口即可,而不需要修改已有的代码。
  4. 避免破坏子类的先决条件:子类必须满足其父类的先决条件。如果子类修改了父类的行为,那么子类就不能替代其父类,这会导致代码的耦合度增加。

4、违反里氏替换原则的反模式

在设计子类时,要遵守父类的行为约定(或者为协议)
以下是违反里氏替换原则的例子:

  1. 子类违反父类声明要实现的功能
  2. 子类违反父类对输入、输出和异常约定
  3. 子类违反父类注释中罗列的任何特殊说明

5、案例解读

假设我们有一个License类,其结构如图1所示。该类中有一个名为calcFee的方法,该方法将由 Billing应用程序来调用。而License类有两个子类型:PersonalLicense与BusinnessLicense,这两个类会用不同的算法来计算授权费用。
在这里插入图片描述

图1:License类与其衍生类,体现了LSP原则

上述设计符合LSP原则,因为Billing应用程序的行为并不依赖于其使用的任何一个衍生类。也就是说,这两个衍生类的对象都是可以用来替换License类对象的。

正方形/长方形问题是一个著名的违反LSP设计原则的案例,该问题结构如图2所示。
在这里插入图片描述

图2:正方形/长方形问题,违反了LSP原则
在这个案例中,Square类并不是Rectangle类的子类型,因为Rectangle类的高和宽可以分别修改,而Square类的高和宽则必须一同修改。由于User类始终认为自己在操作Rectangle类,因此会带来一些混淆。例如在下面的代码中:
Rectangle r = ...
r.setW(5);
r.setH(2);
assert(r.area() == 10);

很显然,如果上述代码在…处返回的是Square类,则最后assert是不会成立的。

6、里氏替换原则与多态的区别

多态是一种代码实现思路,而里氏替换原则是一种设计原则,用来指导继承关系中子类的设计:在替换父类时,确保不改变程序原有的逻辑行为,以及不破坏程序的正确性。

7、小结

里氏替换原则存在的意义:

  • 提高代码的可维护性。遵循里氏替换原则可以使代码的结构更加清晰,如果程序中的对象可以互相替换,那么维护代码的时候就能够更方便地进行修改和扩展。
  • 提高代码的可扩展性。遵循里氏替换原则,可以使代码更容易扩展。如果代码中的对象可以互相替换,那么新的子类可以很容易地替换已有的类,从而实现代码的扩展,而不需要修改原有的代码。
  • 增加代码的可读性。如果遵循里氏替换原则,代码中的类之间的关系会更加清晰明了,这对于其他开发人员来说也更容易理解和阅读。
  • 提高代码的健壮性。遵循里氏替换原则可以使程序更加健壮。如果程序中的对象可以互相替换,那么程序的稳定性和可靠性也会得到提高。
  • 促进代码重用。遵循里氏替换原则,可以使代码更容易重用。如果程序中的对象可以互相替换,那么可以将已有的对象用于新的场景中,从而避免了重复编写代码的情况。

http://www.ppmy.cn/news/172074.html

相关文章

Goby 漏洞更新 |海康威视部分iVMS系统存在文件上传漏洞

漏洞名称:海康威视部分iVMS系统存在文件上传漏洞 English Name:Some Hikvision iVMS file upload vulnerabilitie CVSS core: 9.8 影响资产数:15294 漏洞描述: 海康威视-iVMS综合安防管理平台是一套“集成化”、“数字化”、…

三菱FX3U——SFC单流程的使用

梯形图块中,LD M8002 SET S0;上电第一个上升沿置位S0; SFC中编写SFC流程和动作; PLC运行后,S0得电,等待转移0的条件满足; M0导通后转移; 步20得电,执行其中的动作&…

工控之台达HMI和三菱FX PLC连接

1.硬件准备 1.台达人机:DOP-B03E211;三菱PLC FX-3GE HMI设置: 一小段PLC程序: 注:PLC用的是编程口,三菱FX的编程口通讯是 RS422,通讯线链接: 威纶触摸屏MT6070接三菱FX系列PLC通讯线MT6000-FXTK6100-FX-淘宝网 (taobao.com)

三菱FX3U——SFC跳转的使用

PLC上电后S0得电; 转移0:M0导通后转移,步10得电; 步10得电,y10得电,定时器T0计时;计时到达后,D0加1; 转移5:T0计时到达,并且D0中的数值小于等于3&…

三菱PLC Q、L、FX系列PLC区别

Q系列是模块组合式PLC,有基板、电源、cpu、IO模块、各种智能模块组成,中型大型PLC, IO控制数量多(最多4095),可拓展模块丰富(最多64块),具备强大的网络通讯功能&#xff…

三菱FX3UFX2NFX1N PLC 模拟器模拟通信功能,模拟PLC实体,FX3U仿真器,仿真PLC服务器

三菱FX3UFX2NFX1N PLC 模拟器模拟通信功能,模拟PLC实体,FX3U仿真器,仿真PLC服务器。 支持虚拟串口通信模拟器。 模拟串口通讯,通过虚拟串口实现。 虚拟串口成对使用,如模拟器设置COM3编程请使用COM4。 本产品为软件产品…

三菱PLC——Q系列和FX3U系列通讯测试

目录 一、介绍 二、代码 三、其他 一、介绍 主要用于三菱PLC(Q系列和FX3U系列)测试通讯:测试连接、读取数据、写入数据。 下图中的通讯类型:MC1E(三菱FX3U系列通讯);MC3E(三菱Q系…

三菱PLC(FX2N系列)基本指令

三菱PLC(FX2N系列)基本指令