• 六大设计原则-里氏替换原则


    2.里氏替换原则(Liskov Substitution Principle)(LSP)
    定义: 所有引用基类的地方必须能透明的使用子类对象
    里氏替换原则:就是说当在程序中将一个对象替换成他的子类时,程序可以继续原有的行为,他察觉不出符类和子类的区别。但是反过来却不成立,如果一个程序使用的是一个子类的话,他不一定适用于父类。
    以电脑举例:电脑有CPU,电脑就是程序实体,CPU就是它使用的基类,CPU又有子类IntelCpu。
    public class Cpu {
    
        public void work(){
            System.out.println("CPU在工作");
        }
    }
    public class IntelCpu extends Cpu {
        @Override
        public void work() {
            System.out.println("英特尔CPU工作");
        }
    }
    public class Computer {
    
        private Cpu cpu;
    
        public void run() {
            this.cpu.work();
        }
    
        public Cpu getCpu() {
            return cpu;
        }
    
        public void setCpu(Cpu cpu) {
            this.cpu = cpu;
        }
    }
    电脑依赖的是父类,此时将Cpu换成Intel类型的,电脑仍能正常工作,它察觉不到任何改变,这符合里氏替换原则。  
    而反过来,假设现在有一台电脑,它只能使用IntelCpu才能工作。
    public class IntelCpuComputer {
        private IntelCpu cpu;
        
        public void run() {
            this.cpu.work();
        }
    
        public IntelCpu getCpu() {
            return cpu;
        }
    
        public void setCpu(IntelCpu cpu) {
            this.cpu = cpu;
        }
    }
    如果此时将IntelCpu替换成父类CPU,那么计算机就不能正常工作,因为它只有在使用IntelCpu时才能正常工作。
    public static void main(String[] args) {
          IntelCpuComputer computer = new IntelCpuComputer();
          computer.setCpu(new Cpu());//报错
      }
    再比如说,我们都知道在数学上正方形是特殊的长方形,那么能不能说正方形就是长方形的子类呢?  
    我们用代码表示一下正方形和长方形:
    /**
     * 长方形
     * @author ZhaoShuai
     * @date Create in 2020/4/12
     **/
    public class Rectangle {
    
        private Integer height;
        private Integer width;
    
        public Integer getHeight() {
            return height;
        }
    
        public void setHeight(Integer height) {
            this.height = height;
        }
    
        public Integer getWidth() {
            return width;
        }
    
        public void setWidth(Integer width) {
            this.width = width;
        }
    }
    /**
     * 正方形
     * @author ZhaoShuai
     * @date Create in 2020/4/12
     **/
    public class Square {
        
        private Integer side;
    
        public Integer getSide() {
            return side;
        }
    
        public void setSide(Integer side) {
            this.side = side;
        }
    }
    我们都知道,父类是通过抽取子类的共性封装而成的,从上面代码中可以看出,长方形和正方形的结构式不同的,长方形有长和宽的属性,而正方形只有变长的属性。
    因此,正方形不是长方形的子类,当然也可以强行来继承长方形作为父类,但是我们不是为了继承而继承,这种为了继承而继承的情况也是不属于里氏替换原则的。
    package com.xiazhi.principle.lsp;
    
    /**
     * @author ZhaoShuai
     * @date Create in 2020/4/12
     **/
    public class SquareExtendsRectangle extends Rectangle {
    
        private Integer side;
    
        @Override
        public void setHeight(Integer height) {
            this.setSide(height);
        }
    
        @Override
        public void setWidth(Integer width) {
            this.setSide(width);
        }
    
        @Override
        public Integer getHeight() {
            return this.getSide();
        }
    
        @Override
        public Integer getWidth() {
            return this.getSide();
        }
    
        public Integer getSide() {
            return side;
        }
    
        public void setSide(Integer side) {
            this.side = side;
        }
    }
    可以看出,我们给正方形强行继承了长方形,然后我们写一个测试类:
     public static void main(String[] args) {
            System.out.println("============长方形==============");
            Rectangle rectangle = new Rectangle();
            rectangle.setHeight(10);
            rectangle.setWidth(20);
            print(rectangle);
    
            System.out.println("============正方形==============");
            Rectangle square = new SquareExtendsRectangle();
            square.setHeight(10);
            print(square);
    
        }
    
        private static void print(Rectangle rectangle) {
            System.out.println("高:"+rectangle.getHeight());
            System.out.println("宽:" + rectangle.getWidth());
        }
    测试后我们发现好像能正常运行,此时我们再加一个方法:
    public static void main(String[] args) {
            System.out.println("============长方形==============");
            Rectangle rectangle = new Rectangle();
            rectangle.setHeight(10);
            rectangle.setWidth(20);
            test(rectangle);
    
            System.out.println("============正方形==============");
            Rectangle square = new SquareExtendsRectangle();
            square.setHeight(10);
            test(square);
    
        }
    
        private static void print(Rectangle rectangle) {
            System.out.println("高:"+rectangle.getHeight());
            System.out.println("宽:" + rectangle.getWidth());
        }
    
        private static void test(Rectangle rectangle) {
            while (rectangle.getWidth() >= rectangle.getHeight()) {
                rectangle.setHeight(rectangle.getHeight()+1);
                print(rectangle);
            }
        }
    运行后可以发现, 长方形可以正常运行,而正方形却会出现死循环,因此这种是不符合里氏替换原则的。因为引用父类的地方无法使用子类对象。
    在类的设计时,根据依赖倒置原则,要使用抽象类或接口,如果不能使用抽象类或者接口,那么就说明设计违背了里氏替换原则(LSP)
  • 相关阅读:
    FFT加速多项式乘法C语言版(基2FFT)
    springboot2中@ConfigurationProperties装载yml文件的时候调取出现值为null的解决办法
    LeetCode27-移除元素
    dom4j在解析xml文件的时候将" "解析成空格的解决办法
    LeetCode17- 电话号码的字母组合
    LeetCode19- 删除链表的倒数第N个节点
    LeetCode14- 最长公共前缀
    LeetCode20- 有效的括号
    LeetCode21- 合并两个有序链表
    MySQL单表百万数据记录分页性能优化
  • 原文地址:https://www.cnblogs.com/Zs-book1/p/12714021.html
Copyright © 2020-2023  润新知