软件设计七大原则之里氏替换原则

本文通过实例解析里氏替换原则,展示了如何避免在继承关系中导致的问题,如几维鸟重写飞行方法。通过创建Animal、Bird、Swallow和BrownKiwi类,以及QuardRangle接口,演示了如何正确维护代码的灵活性和一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

里氏替换原则

简单描述:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。

几维鸟不是鸟

分析:鸟一般都会飞行,如燕子的飞行速度大概是每小时 120 千米。但是新西兰的几维鸟由于翅膀退化无法飞行。
假如要设计一个实例,计算这两种鸟飞行 300 千米要花费的时间。显然,拿燕子来测试这段代码,结果正确,能计算出所需要的时间;
但拿几维鸟来测试,结果会发生“除零异常”或是“无穷大”。
几维鸟类重写了鸟类的 setSpeed(double speed) 方法,这违背了里氏替换原则。
正确的做法是:取消几维鸟原来的继承关系,定义鸟和几维鸟的更一般的父类,如动物类,它们都有奔跑的能力。
几维鸟的飞行速度虽然为 0,但奔跑速度不为 0,可以计算出其奔跑 300 千米所要花费的时间。
UML类图如下。
在这里插入图片描述
1.新建animal类

public class Animal {
    private double runSpeed;

    public void setRunSpeed(double runSpeed){
        this.runSpeed = runSpeed;
    }

    public double getRunTime(double distance){
        return distance/this.runSpeed;
    }
}

2.新建Bird(鸟类)及Swallow(燕子)

public class Bird extends Animal {
    private double flySpeed;

    public void setFlySpeed(double flySpeed){
        this.flySpeed = flySpeed;
    }

    public double getFlyTime(double distance){
        return distance/this.flySpeed;
    }
}
// 燕子
public class Swallow extends Bird {
}

3.新建几维鸟

public class BrownKiwi extends Animal {
}

4.新建主类运行

 		Bird swallow = new Swallow();
        swallow.setFlySpeed(120);
        double flyTime = swallow.getFlyTime(300);

        Animal brownKiwi = new BrownKiwi();
        brownKiwi.setRunSpeed(50);
        double runTime = brownKiwi.getRunTime(300);

        System.out.println("燕子飞行时间:" + flyTime);
        System.out.println("几维鸟跑步时间:" + runTime);

在这里插入图片描述

用正方形、矩形和四边形的关系来说明里氏替换原则。

1.新建长方形类Rectangle

public class Rectangle {

    /**
     * 高
     */
    long height;

    /**
     * 宽
     */
    long width;

    public long getHeight() {
        return height;
    }

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

    public long getWidth() {
        return width;
    }

    public void setWidth(long width) {
        this.width = width;
    }
}

2.新建正方形类

public class Square extends Rectangle {

    private long length;

    public long getLength() {
        return length;
    }

    public void setLength(long length) {
        this.length = length;
    }

    @Override
    public long getHeight() {
        return getLength();
    }

    @Override
    public void setHeight(long height) {
        setLength(height);
    }

    @Override
    public void setWidth(long width) {
        setLength(width);
    }

    @Override
    public long getWidth() {
        return getLength();
    }
}

3.新建扩容方法

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 End,width:" + rectangle.getWidth() +
            " ,Height:" + rectangle.getHeight());

}

4.测试

 Rectangle rectangle = new Rectangle();
        rectangle.setWidth(20);
        rectangle.setHeight(10);
        resize(rectangle);

在这里插入图片描述
由运行结果可知,高比宽还大,这在长方形中是一种非常正常的情况。再看下面的代码,把长方形替换成它的子类正方形,修改客户端测试代码如下

Square square = new Square();
        square.setLength(10);
        resize(square);

此时,运行出现了死循环,违背了里氏替换原则,在将父类替换成子类后,程序运行结果没有达到预期。

里氏替换原则只存在于父类和子类之间,约束继承泛滥。再来创建一个基于长方形与正方形共同的抽象——四边形 QuardRangle 接口,代码如下。

public interface QuardRangle {
    long getWidth();
    long getHeight();
}

修改长方形 Rectangle 类的代码如下。

 private long height;    //高
    private long width;    //宽

    @Override
    public long getHeight() {
        return height;
    }
    public void setHeight(long height) {
        this.height = height;
    }
    public void setWidth(long width) {
        this.width = width;
    }
    @Override
    public long getWidth() {
        return width;
    }

修改正方形 Square 类的代码如下。

public class Square implements QuardRangle {
    private long length;
    public long getLength() {
        return length;
    }
    public void setLength(long length) {
        this.length = length;
    }
    @Override
    public long getHeight() {
        return getLength();
    }
    @Override
    public long getWidth() {
        return getLength();
    }
}

此时,如果把 resize() 方法的参数换成四边形 QuardRangle 类,方法内部就会报错。因为正方形已经没有了 setWidth() 和 setHeight() 方法,所以,为了约束继承泛滥,resize() 方法的参数只能用长方形 Rectangle 类。
参考资料:
1.http://c.biancheng.net/view/1324.html
代码地址:https://gitee.com/zhoujie1/design-mode-and-principle.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值