里氏替换准则(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弹架构”,回复“材料”、“简历”、“刷题”,“招聘”即可支付面试真题,简历模板等!