Liskov Substitution Principle 里氏替换原则

Liskov Substitution Principle 里氏替换原则

简介

定义:如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都替换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型,
定义扩展:一个软件实体如果使用一个父类的话,那一定适用于其子类,所有引用父类的地方必须能透明地使用其子类的对象,子类对象能够替代父类对象,而程序逻辑不变。

主要核心思想

强调只和朋友交流,不和陌生人说话
朋友:出现在成员变量、方法的输入、输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。
引申意义:子类可以扩展父类的功能,但不能改变父类原有的功能
含义1:子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
含义2:子类中可以增加自己特有的方法
含义3:当子类的方法重载父类的方法时,方法的前置条件(即方法的输入、入参)要比父类方法的输入参数更宽松
含义4:当子类的条件实现父类的方法时(重写、重载或实现抽象方法),方法的后置条件(即方法的输出、返回值)要比父类更严格或相等。

优点

  • 约束继承泛滥,开闭原则的一种体现
  • 加强程序的健壮性,同时变更时也可以做到非常好的兼容性提高程序性的维护性,扩展性。
  • 降低需求变更时引入的风险

实践案例

类层面:正方形、长方形
方法层面:含义3
返回值层面:含义4

类层面:正方形、长方形
public interface QuadRangle {
    Integer getHeight();
    Integer getWidth();
}
public class Rectangle implements QuadRangle {

    private Integer height;

    private Integer width;

    @Override
    public Integer getHeight() {
        return this.height;
    }

    @Override
    public Integer getWidth() {
        return this.width;
    }

    public void setHeight(Integer height) {
        this.height = height;
    }

    public void setWidth(Integer width) {
        this.width = width;
    }
}
public class Square implements QuadRangle {

    private Integer length;

    @Override
    public Integer getHeight() {
        return this.length;
    }

    @Override
    public Integer getWidth() {
        return this.length;
    }

    public Integer getLength() {
        return length;
    }

    public void setLength(Integer length) {
        this.length = length;
    }
}
public class LspTest {


    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());
        }
    }

    public static void main(String[] args) {
//        Rectangle rectangle = new Rectangle();
//        rectangle.setHeight(10);
//        rectangle.setWidth(20);
//        resize(rectangle);

        Square square = new Square();
        square.setLength(20);
//        resize(square);
    }
}

Liskov Substitution Principle 里氏替换原则_第1张图片

上面类图与下面类图为代码编写的两种情况,一种是以长方形为父类,另一种是以正方形为父类

方法层面:含义3
public class Base {

//    public void method(HashMap map) {
//        System.out.println("执行父类HashMap参数的方法");
//    }

    public void method(Map map) {
        System.out.println("执行父类Map参数的方法");
    }
}
public class Child extends Base {

    public void method(HashMap map) {
        System.out.println("执行子类HashMap参数的方法");
    }

//    public void method(Map map) {
//        System.out.println("执行子类Map参数的方法");
//    }
}
public class MethodTest {

    public static void main(String[] args) {
        HashMap map = new HashMap();
        Base base = new Child();
        base.method(map);
    }
}

当父类方法入参比子类大时,即父类 method 方法 入参为Map,而子类为HashMap
Base base = new Child(); base.method(map); 调用的是父类的 method 方法
Child base = new Child(); base.method(map); 调用的是子类的 method 方法

返回值层面:含义4
public abstract class Base {
    public abstract Map getMap();
}
public class Child extends Base {
    @Override
    public HashMap getMap() {
        HashMap hashMap = new HashMap();
        System.out.println("执行子类的getMap()方法");
        hashMap.put("msg", "执行成功");
        return hashMap;
    }
}
public class MethodReturnTest {
    public static void main(String[] args) {
        Base base = new Child();
        Map map = base.getMap();
        System.out.println(map.get("msg"));
    }
}

父类方法返回值类型为Map,子类重写父类方法,修改其返回值类型为HashMap,测试运行成功

你可能感兴趣的:(设计模式,java,里氏替换原则,里氏替代原则)