1.里氏代换原则简介
里氏替换原则( Liskov Substitution Principle 简称LSP)是指:一个软件实体如果使用的是基类的话, 那么也一定适用于其子类, 而且它根本觉察不错使用的是基类对象还是子类对象; 反过来的代换这是不成立的, 即: 如果一个软件实体使用一个类的子类对象,那么它不能够适用于基类对象。
里氏代换原则是实现开放封闭原则的具体规范。这是因为: 实现开放封闭原则的关键是进行抽象,而继承关系又是抽象的一种具体实现,这样LSP就可以确保基类和子类关系的正确性,进而为实现开放封闭原则服务。
定义1:如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。
定义2:所有引用基类的地方必须能透明地使用其子类的对象。
2.图解
3.代码说明
需求:先求两个数的和
基类
public class FatherNumber {
public int add(int num1,int num2){
return num1+num2;
}
}
调用
FatherNumber fatherNumber=new FatherNumber();
int result=fatherNumber.add(10,20);
Log.d("TAG","result----:"+result);
结果
result----:30
再简单不过的基本知识,再次不做过多赘述。
先有一个子类继承了上面的父类并自己新加减法的功能
子类
public class SonNumber extends FatherNumber{
@Override
public int add(int num1, int num2) {
return super.add(num1, num2);
}
public int minus(int num1,int num2){
return num1-num2;
}
}
调用
FatherNumber fatherNumber=new FatherNumber();
int result1=fatherNumber.add(10,20);
Log.d("TAG","调用父类10+20="+result1);
SonNumber sonNumber=new SonNumber();
int result2=sonNumber.add(10,20);
Log.d("TAG","调用子类10+20="+result2);
int result3=sonNumber.minus(20,10);
Log.d("TAG","子类20-10="+result3);
结果
调用父类10+20=30
调用子类10+20=30
子类20-10=10
由此可知子类集成了父类 重写了父类的方法,但是没有修改父类的方法。所以无论用父类的加法还是子类的加法都是正确的。
新子类
public class SonNumber extends FatherNumber{
@Override
public int add(int num1, int num2) {
return num1*num2;
}
public int minus(int num1,int num2){
return (num1-num2)+add(num1,num2);
}
}
它修改了父类的加方法将 num1+num2 改成 num1*num2
调用
FatherNumber fatherNumber=new FatherNumber();
int result1=fatherNumber.add(10,20);
Log.d("TAG","调用父类10+20="+result1);
SonNumber sonNumber=new SonNumber();
int result2=sonNumber.add(10,20);
Log.d("TAG","调用子类10+20="+result2);
int result3=sonNumber.minus(20,10);
Log.d("TAG","子类(20-10)+(20+10)="+result3);
结果
调用父类10+20=30
调用子类10+20=200
子类(20-10)+(20+10)=210
由上可知按照子类(由于将加法改成乘法) 即10*20=200 (20-10)*(20*10)=210 是没有问题的。可是如果按照父类加法就是加法 10+20=200 (20-10)+(20+10)=210 显然是不正确的。
4.总结
里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:
子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
子类中可以增加自己特有的方法。
当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
里氏代换原则是很多其它设计模式的基础。它和开放封闭原则的联系尤其紧密。违背了里氏代换原则就一定不符合开放封闭原则。