• 设计原则 里氏替换原则


    概念

    • 里氏替换原则(Liskov Substitution Principle, LSP):一个软件实体如果适用一个父类的话,那一定适用于其子类,所有引用父类的地方必须能透明地使用其子类的对象,子类对象能够替换父类对象,而程序逻辑不变。

    • 里氏替换原则表眀,在软件中将一个基类对象替换成他的子类对象,程序将不会产生任何错误和异常,反之则不成立;如果一个软件实体使用的是一个子类对象,那么它不一定能够使用基类对象。例如,张三喜欢动物,那张三一定喜欢狗,因为狗是动物的子类;如果张三喜欢狗,不能据此断定张三喜欢动物。

    • 优点1:约束继承泛滥,开闭原则的一种体现。

    • 优点2:加强程序的健壮性,同时变更时也可以做到非常好的兼容性,提高程序的维护性、扩展性。降低需求变更时引入的风险。


    编码

    实例

    • 验证正方形是不是特殊的长方形
    • Rectangle.java
    /**
     * @Description 长方形
     * @date Dec 15, 2021
     * @Version 1.0
     */
    public class Rectangle {
    
        private long length;
        private long width;
    
        public long getLength() {
            return length;
        }
    
        public void setLength(long length) {
            this.length = length;
        }
    
        public long getWidth() {
            return width;
        }
    
        public void setWidth(long width) {
            this.width = width;
        }
    }
    
    • Square.java
    /**
     * @Description 正方形
     * @date Dec 15, 2021
     * @Version 1.0
     */
    public class Square extends Rectangle{
    
        /**
         * 边长
         */
        private long sideLength;
    
        public long getSideLength() {
            return sideLength;
        }
    
        public void setSideLength(long sideLength) {
            this.sideLength = sideLength;
        }
    
        @Override
        public long getLength() {
            return getSideLength();
        }
    
        @Override
        public void setLength(long length) {
            setSideLength(length);
        }
    
        @Override
        public long getWidth() {
            return getSideLength();
        }
    
        @Override
        public void setWidth(long width) {
            setSideLength(width);
        }
    }
    
    • Test.java
    /**
     * @Description 测试类
     * @date Dec 15, 2021
     * @Version 1.0
     */
    public class Test {
    
        /**
         * 调整大小
         * 当宽小于等于长的时候给宽度+1,直到它们相等
         * @param rectangle
         */
        public static void resize(Rectangle rectangle) {
            while (rectangle.getWidth() <= rectangle.getLength()) {
                rectangle.setWidth(rectangle.getWidth() + 1);
                System.out.println(" " + rectangle.getWidth() + " length: " + rectangle.getLength());
            }
    
            System.out.println("resize end,  " + rectangle.getWidth() + " length: " + rectangle.getLength());
        }
    }
    
    • 长方形(基类)验证
    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle();
        rectangle.setWidth(10);
        rectangle.setLength(20);
        resize(rectangle);
    }
    
    • 输出如下,程序正常执行:
     11 length: 20
     12 length: 20
     13 length: 20
     14 length: 20
     15 length: 20
     16 length: 20
     17 length: 20
     18 length: 20
     19 length: 20
     20 length: 20
     21 length: 20
    resize end,  21 length: 20
    
    • 正方形(子类)验证
    /**
     * 正方形(子类)验证
     * @param args
     */
    public static void main(String[] args) {
        Square square = new Square();
        square.setLength(10);
        resize(square);
    }
    
    • 输出如下,方法会无穷无境的进行下去,直到溢出,当我们将父类替换成子类进行执行的时候,程序运行的期望和我们所期望的是不一样的,这里的程序设计违反了里氏替换原则
     11 length: 11
     12 length: 12
     13 length: 13
     14 length: 14
     15 length: 15
     16 length: 16
     17 length: 17
     18 length: 18
     19 length: 19
     20 length: 20
     21 length: 21
     22 length: 22
     23 length: 23
     24 length: 24
     25 length: 25
     26 length: 26
     27 length: 27
     28 length: 28
    ....................
    

    里氏替换原则

    • 创建新的四边形类,解除长方形和正方形的继承关系
    • Quadrangle.java
    /**
     * @Description 四边形
     * @date Dec 19, 2021
     * @version 1.0
     */
    public interface Quadrangle {
    
        long getWidth();
    
        long getLength();
    
    }
    
    • Rectangle.java
    /**
     * @Description 长方形
     * @date Dec 15, 2021
     * @Version 1.0
     */
    public class Rectangle implements Quadrangle {
    
        private long length;
        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.java
    /**
     * @Description 正方形
     * @date Dec 15, 2021
     * @Version 1.0
     */
    public class Square implements Quadrangle {
    
        /**
         * 边长
         */
        private long sideLength;
    
        @Override
        public long getWidth() {
            return sideLength;
        }
    
        @Override
        public long getLength() {
            return sideLength;
        }
    
        public long getSideLength() {
            return sideLength;
        }
    
        public void setSideLength(long sideLength) {
            this.sideLength = sideLength;
        }
    }
    
    • Test.java

    在这里插入图片描述

    • 可以看到,通过四边形,get方法时ok的,set方法却是不行的,因为四边形接口中并没有申明set长和宽,秘密在于父类并没有赋值方法,整个resize方法是不适用于四边形类型的,该方法中提出了约束,禁止继承泛滥

    总结

    • 里氏替换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象

    • 在运用里氏替换原则时,应该将父类设计为抽象类或接口,让子类继承父类或实现父接口并实现在父类中声明的方法,程序运行时,子类实例替换父类实例,可以很方便地扩展系统的功能,无需修改原有子类的代码,增加新的功能可以通过增加新的子类来实现。


    源码


    - End -
    - 个人学习笔记 -

    以上为本篇文章的主要内容,希望大家多提意见,如果喜欢记得点个推荐哦
    作者:Maggieq8324
    本文版权归作者和博客园共有,欢迎转载,转载时保留原作者和文章地址即可。
  • 相关阅读:
    BZOJ 1854: [Scoi2010]游戏( 二分图最大匹配 )
    BZOJ 2038: [2009国家集训队]小Z的袜子(hose) ( 莫队 )
    BZOJ 3555: [Ctsc2014]企鹅QQ( hash )
    BZOJ 2226: [Spoj 5971] LCMSum( 数论 )
    BZOJ 3505: [Cqoi2014]数三角形( 组合数 )
    BZOJ 2510: 弱题( 矩阵快速幂 )
    BZOJ 1009: [HNOI2008]GT考试( dp + 矩阵快速幂 + kmp )
    BZOJ 1090: [SCOI2003]字符串折叠( 区间dp )
    HDU 2295 Radar dancing links 重复覆盖
    ZOJ 3209 Treasure Map dancing links
  • 原文地址:https://www.cnblogs.com/maggieq8324/p/15782984.html
Copyright © 2020-2023  润新知