里氏代换原则(LSP)
从“开-闭”原则中可看出面向对象设计的重要原则是创建抽象化,并且从抽象化导出具体化。具体化可以给出不同的版本,每一个版本都给出不同的实现。
从抽象化到具体化的导出要使用继承关系和里氏代换原则(Liskove Substitution Principle,常缩写为LSP)。
里氏代换原则的定义:如果对每个类型为t1的对象o1,都有类型为t2的对象o2,使得以t1定义的所有程序p在所有的对象o1都代换成o2时,程序p的行为没有变化,那么类型t2是类型t1的子类型。
一个软件实体可以使用基类的时候,也可以使用其子类。
里氏代换原则是继承复用的基石。只有当衍生类可以替换掉基类,软件单位的功能不会受到影响时,基类才能真正被复用,而衍生类也才能够在基类基础上增加新的行为。
反过来不成立。
里氏代换要求凡是基类型使用的地方,子类型一定适用,因此子类型必须具备基类型的全部接口。或者说,子类型的接口必须包括全部的基类型的接口,而且还可能更宽(访问权限可以放大,不可以缩小)。
Java语言编译器对精度检查,但是不能检查准确度(与真实事物的相符合的程度)。
里氏代换原则在设计模式中的体现
策略模式:
如果有一组算法,就将每个算法封装起来,使得它们可以互换。
要互换,就需要将所有的具体策略角色放到一个类型等级结构中,使它们拥有共同的接口。这种互换性依赖的是对里氏代换原则的遵守:
AbstractStrategy s = new ConcreteStrategyA();
客户端依赖于基类类型,而对象的类型是具体策略类。这是具体策略角色可以“即插即用”的关键。
合成模式:
通过树结构描述整体与部分的关系,从而可以将单纯元素与复合元素同等看待。由于单纯元素和复合元素都是抽象元素角色的子类,因此两者都可替代抽象元素出现在任何地方。
代理模式:
代理模式给某个对象提供一个代理对象,并由代理对象控制对原对象的引用。代理模式能够成立的关键,就在于代理模式与真实主题模式都是抽象主题角色的子类。客户端只知道抽象主题,而代理主题可以替代抽象主题出现在任何需要的地方,而将真实主题隐藏在幕后。
在代码重构的应用:
里氏代换原则讲的是基类与子类的关系。只有当这种关系存在时,里氏代换关系才存在;反之不存在。如果两个具体类A和B之间的关系违反了里氏代换原则的设计,根据具体情况可以在下面的两种重构方案中选择一种:
1)创建一个新的抽象类C,作为两个具体类的超类,将A和B的共同行为移动到C中,从而解决A和B行为不完全一致的问题:
2)从B到A的继承关系改写成委派关系:
从抽象类继承:
应当尽量从抽象类继承,而不从具体类继承。如果两个具体类A和B有继承关系,最简单的修改方案应当是建立一个抽象类C,然后让类A和类B成为抽象类C的子类。
子类应该具备父类所有的行为。
声明: 除非转自他站(如有侵权,请联系处理)外,本文采用 BY-NC-SA 协议进行授权 | 嗅谱网
转载请注明:转自《里氏代换原则(LSP)》
本文地址:http://www.xiupu.net/archives-8011.html
关注公众号:
微信赞赏
支付宝赞赏