里氏替换准则(Liskov Substitution Principle,LSP)是指如果对每一个类型为T1的对象o1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有的对象O1都替换成O2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。
这个定义看上去还是比拟形象的,咱们从新了解一下。能够了解为一个软件实体如果实用于一个父类,那么肯定实用于其子类,所有援用父类的中央必须能通明地应用其子类的对象,子类对象可能替换父类对象,而程序逻辑不变。依据这个了解,引申含意为:子类能够扩大父类的性能,但不能扭转父类原有的性能。
(1)子类能够实现父类的形象办法,但不能笼罩父类的非形象办法。
(2)子类能够减少本人特有的办法。
(3)当子类的办法重载父类的办法时,办法的前置条件(即办法的输出/入参)要比父类办法的输出参数更宽松。
(4)当子类的办法实现父类的办法时(重写/重载或实现形象办法),办法的后置条件(即办法的输入/返回值)要比父类更严格或与父类一样。
在讲开闭准则的时候我埋下了一个伏笔,在获取折扣时重写笼罩了父类的getPrice()办法,减少了一个获取源码的办法getOriginPrice(),显然就违反了里氏替换准则。咱们批改一下代码,不应该笼罩getPrice()办法,减少getDiscountPrice()办法:
public class JavaDiscountCourse extends JavaCourse {
public JavaDiscountCourse(Integer id, String name, Double price) {
super(id, name, price);
}
public Double getDiscountPrice(){
return super.getPrice() * 0.61;
}
}
应用里氏替换准则有以下长处:
(1)束缚继承泛滥,是开闭准则的一种体现。
(2)增强程序的健壮性,同时变更时也能够做到十分好的兼容性,进步程序的可维护性和扩展性,升高需要变更时引入的危险。
当初来形容一个经典的业务场景,用正方形、矩形和四边形的关系阐明里氏替换准则,咱们都晓得正方形是一个非凡的长方形,所以就能够创立一个父类Rectangle:
public class Rectangle {
private long height;
private long width;
@Override
public long getWidth() {
return width;
}
@Override
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
}
public void setWidth(long width) {
this.width = width;
}
}
创立正方形类Square继承Rectangle类:
public class Square extends Rectangle {
private long length;
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
}
@Override
public long getWidth() {
return getLength();
}
@Override
public long getHeight() {
return getLength();
}
@Override
public void setHeight(long height) {
setLength(height);
}
@Override
public void setWidth(long width) {
setLength(width);
}
}
在测试类中创立resize()办法,长方形的宽应该大于等于高,咱们让高始终自增,直到低等于宽,变成正方形:
public static void resize(Rectangle rectangle){
while (rectangle.getWidth() >= rectangle.getHeight()){
rectangle.setHeight(rectangle.getHeight() + 1);
System.out.println("width:"+rectangle.getWidth() + ",height:"+rectangle.getHeight());
}
System.out.println("resize办法完结" +
"\nwidth:"+rectangle.getWidth() + ",height:"+rectangle.getHeight());
}
测试代码如下:
public static void main(String[] args) {
Rectangle rectangle = new Rectangle();
rectangle.setWidth(20);
rectangle.setHeight(10);
resize(rectangle);
}
运行后果如下图所示。
咱们发现高比宽还大了,这在长方形中是一种十分失常的状况。当初咱们把Rectangle类替换成它的子类Square,批改测试代码:
public static void main(String[] args) {
Square square = new Square();
square.setLength(10);
resize(square);
}
上述代码运行时呈现了死循环,违反了里氏替换准则,将父类替换为子类后,程序运行后果没有达到预期。因而,咱们的代码设计是存在肯定危险的。里氏替换准则只存在于父类与子类之间,束缚继承泛滥。咱们再来创立一个基于长方形与正方形独特的形象四边形接口Quadrangle:
public interface Quadrangle {
long getWidth();
long getHeight();
}
批改长方形类Rectangle:
public class Rectangle implements Quadrangle {
private long height;
private long width;
@Override
public long getWidth() {
return width;
}
public long getHeight() {
return height;
}
public void setHeight(long height) {
this.height = height;
}
public void setWidth(long width) {
this.width = width;
}
}
批改正方形类Square:
public class Square implements Quadrangle {
private long length;
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
}
@Override
public long getWidth() {
return length;
}
@Override
public long getHeight() {
return length;
}
}
此时,如果咱们把resize()办法的参数换成四边形接口Quadrangle,办法外部就会报错。因为正方形类Square曾经没有了setWidth()和setHeight()办法。因而,为了束缚继承泛滥,resize()办法的参数只能用Rectangle类。当然,咱们在前面的设计模式的内容中还会持续深刻解说。
小测一下
本文为原创文章,转载请注明出处!关注微信公众号“Tom弹架构”,回复“材料”、“简历”、“刷题”,“招聘”即可支付面试真题,简历模板等!
发表回复