里氏替换原则(Liskov Substitution Principle,LSP)
里氏替换原则(Liskov Substitution Principle,LSP)由芭芭拉·利斯科夫(Barbara Liskov)首先提出,其原文如下。
Let q(x) be a property provable about objects x of type T. Then q(y) should be true for objects y of type S where S is a subtype of T.
中文直译的意思是:设q(x)是类型T的对象x的属性,那么q(y)对于类型T的子类型S的对象y应该为真
。
再翻一次的意思是:派生类(子类)对象可以在程序中代替其基类(超类)对象
。
这种表述基本等于没说,但其实它包含了两层意思。
一是
可以用子类替换父类,但不能用父类替换子类
。二是
子类可以扩展父类的功能,但是不能改变父类原有的功能
。
例如,存在这样的继承结构。

IBase
是整个支付系统的公共父类,它有一个子类接口IPay
,ThirdPay
作为IPay
的直接子类,实现了接口的方法,而Alipay
是ThirdPay
的直接子类。
现在存在用户类User
,假设它有这样一个方法。
package com.itechthink.designrule.lireplace;
/**
* 用户支付手续费
*
*/
public class User {
public void getCharge(IPay iPay) {
System.out.println(iPay.getCharge());
}
}
那么,当调用User
类的方法时,就可以用IPay
的子类来替换它,但不能用它的父类来替换它。
package com.itechthink.designrule.lireplace;
/**
* 里氏替换原则的原始定义比较难于理解,但说直白点就是子类可以扩展父类的功能,但是不能改变父类原有的功能
*
*/
public class LiReplace {
public static void main(String[] args) {
User user = new User();
// 这样是合法的
user.getCharge(new AliPay("AliPay", 0.01));
// 这样也是合法的
user.getCharge(new IPay() {
@Override
public Double getCharge() {
return 0.0;
}
});
// 这样是非法的
user.getCharge(new IBase() {
@Override
public Double getCharge() {
return 0.0;
}
});
}
}
上面的非法调用user.getCharge(new IBase() {...});
显然不满足第一层意思可以用子类替换父类,但不能用父类替换子类
。
而如果合法调用user.getCharge(new IPay() {...});
改变了父类原始设定的手续费率,则又无法满足第二层意思子类可以扩展父类的功能,但是不能改变父类原有的功能
。
例如这样的扩展,就不符合里氏替换原则。
package com.itechthink.designrule.lireplace;
/**
* 支付宝支付
*
*/
public class AliPay extends ThirdPay {
public AliPay(String name, Double charge) {
super(name, charge);
}
// 原手续费
public Double getOriginCharge() {
return super.getCharge();
}
// 现手续费
// 违背了里氏替换原则,修改了父类的方法
public Double getCharge() {
return super.getCharge() * 0.6;
}
// 不修改父类的方法,增加新的方法
public Double getNewCharge() {
return super.getCharge() * 0.6;
}
}
如果这两个需求都能够满足,那么它们合在一起,就是里氏替换原则所描述的意思。
感谢支持
更多内容,请移步《超级个体》。