软件设计原则之LSP里氏替换原则

(LSP) 里氏替换原则 Liskov Substitution Principle

核心原则

子类必须能够替换它们的基类 (IS-A)。

场景描述

我们都知道在数学中正方形是矩形的一种特例。

我们很容易想到可以使用继承关系,即正方形作为子类继承父类矩阵。

复制代码
#include <iostream>

// 矩形基类
class Rectangle {
private:
    double width  = 0;
    double height = 0;

public:
    virtual ~Rectangle() = default;
    Rectangle(double w, double h) {
        width  = w;
        height = h;
    }

    void set_width(double w) {
        width = w;
    }
    void set_height(double h) {
        height = h;
    }
    double get_area() const {
        return width * height;
    };
};

// 正方形继承矩形
class Square : public Rectangle {
public:
    Square(double len) : Rectangle(len, len) {
    }
};

void change_oneside(Rectangle& rect, double len) {
    rect.set_width(len);
}

int main() {
    Square squ(10);
    std::cout << "Square area = " << squ.get_area() << '\n';

    // 希望得到的area是400,但是最终是200
    change_oneside(squ, 20);
    std::cout << "After set length Square area = " << squ.get_area() << '\n';
}

问题暴露

很明显,我们知道矩形可以分别修改长和宽,而正方形所有边都一样。

如果朴素的使用直接继承的设计方案,极容易出现正方形只修改一组平行边,从而退化为矩形的情况。

这就是里氏替换原则的一个经典例子,那如何解决呢?

复制代码
#include <iostream>

// 统一图形的接口
// 空的多态函数,让具体类型实现具体操作
class IGeometry {
public:
    virtual void set_sideLegth(double len) {
    }
    virtual void set_sideLegth(double len1, double len2) {
    }
    virtual double get_area() const {
        return 0;
    };
};

// 矩形
class Rectangle : public IGeometry {
private:
    double width  = 0;
    double height = 0;

public:
    virtual ~Rectangle() = default;
    Rectangle(double w, double h) {
        width  = w;
        height = h;
    }
    virtual void set_sideLegth(double w, double h) override {
        width  = w;
        height = h;
    }
    virtual double get_area() const override {
        return width * height;
    };
};

// 正方形
class Square : public IGeometry {
private:
    double side = 0;

public:
    Square(double len) {
        side = len;
    }
    virtual void set_sideLegth(double len) override {
        side = len;
    }
    virtual double get_area() const override {
        return side * side;
    };
};

void change_oneside(IGeometry& rect, double len) {
    rect.set_sideLegth(len);
}

int main() {
    Square squ(10);
    std::cout << "Square area = " << squ.get_area() << '\n';

    // 希望得到的area是400,但是最终是200
    change_oneside(squ, 20);
    std::cout << "After set length Square area = " << squ.get_area() << '\n';
}
相关推荐
数据知道1 个月前
claw-code 源码分析:从 REPL 到服务端——CLI / HTTP(SSE) / LSP 多入口如何共享同一颗 runtime 心?
python·网络协议·http·ai·里氏替换原则·claude code
WarrenMondeville2 个月前
3.Unity面向对象-里氏替换原则
unity·游戏引擎·里氏替换原则
WeeJot嵌入式2 个月前
Meta LSP无数据训练深度解析:语言自我对弈的数学原理与实现
人工智能·机器学习·里氏替换原则
Hvitur2 个月前
解决报错:eclipse报错:LSP (Spring Boot Language Server)
spring boot·eclipse·里氏替换原则
BD_Marathon3 个月前
设计模式——里氏替换原则
java·设计模式·里氏替换原则
以太浮标3 个月前
华为eNSP综合实验之- MPLS静态LSP标签交换路径
华为·里氏替换原则
怪力左手4 个月前
LSP、DAP语言服务器
运维·服务器·里氏替换原则
MediaTea5 个月前
Python:里氏替换原则(LSP)
里氏替换原则
聊天QQ:276998855 个月前
车桥耦合matlab程序。 使用newmark法进行数值积分,考虑不平顺车辆-无砟轨道-桥梁耦...
里氏替换原则