背景介绍
这是我的《架构整洁之道》系列的第八篇,这一篇我们将一起学习 LSP 里氏替换原则~
《架构整洁之道》系列:
LSP 里氏替换原则
1988 年,Barbara Liskov 在描述如何定义子类型时写下了这样一段话 :
这里需要的是一种可替换性:如果对于每个类型是 S 的对象 o1 都存在一个类型为 T 的对象 o2,能使操作 T 类型的程序 P 在用 o2 替换 o1 时行为保持不变,我们就可以将 S 称为 T 的子类型。
为了理解上面这句话,我举几个例子:
- 案例一
假设我们有一个 License 类,该类中有一个名为 calcFee() 的方法,该方法将由 Billing 应用程序来调用。而 License 类有两 个“子类型”: PersonalL工cense 与 BusinessLicense,这两个类会用不同的算法来计算授权费用。
上述设计是符合 LSP 原则的,因为 Billing 应用程序的行为并不依赖于其使用的任何一个衍生类。也就是说,这两个衍生类的对象都是可以用来替换 License 类对象的。
- 案例二
正方形/长方形问题是一个著名的违反 LSP 的设计案例。在这个案例中,Square 类并不 Rectangle 类的子类型,因为 Rectangle 类的高和宽可以分别修改,而 Square类的高和宽则必须一同修改。由于 User类始终认为自己在操作 Rectangle 类,因此会带来一些泪淆。
如果想要防范这种违反 LSP 的行为,唯一的办法就是在 User 类中增加用于区分 Rectangle 和 Square 的检测逻辑。但这样一来,User 类的行为又将依赖于它所使用的类,这两个类就不能互相替换了。
结束语
在面向对象这场编程革命兴起的早期,我们的普遍认知正如上文所说,认为 LSP 只不过是指导如何使用继承关系的一种方法,然而随着时间的推移,LSP 逐渐演变成了一种更广泛的、指导接口与其实现方式的设计原则。LSP 可以且应该被应用于软件架构层面,因为一旦违背了可替换性,该系统架构就不得不为此增添大量复杂的应对机制。
最后
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
少年向来不识天高地厚
放眼处皆自负才高八斗
虽是自命风流
倒也坦诚无忧
我爱这样的少年
谦和而狂妄
骄傲又坦然☀️
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨