里氏替换原则理解

里氏替换原则(Liskov Substitution Principle, LSP)是面向对象设计中的一个重要原则,它是SOLID 五大设计原则之一。该原则由计算机科学家 Barbara Liskov 提出,核心思想是:

定义:

在一个程序中,如果一个对象属于某个基类 ,那么它的子类应当能够替代基类的对象,且程序的行为不受影响。换句话说,子类应该能够在不改变父类期望行为的前提下,替换父类对象。

具体含义:

  • 子类应该继承父类,并且能够扩展父类的功能,而不是去破坏父类的功能。
  • 子类的行为应当和父类的行为一致,或者在父类的基础上提供更多功能,而不是修改父类行为的本质。
  • 任何依赖于基类的代码在使用子类时,都不应该出现错误或异常。

违反里氏替换原则的情况:

  • 行为不一致:子类重写父类的方法时,改变了父类方法的行为,导致原本能正常工作的代码出现异常或不符合预期的结果。
  • 异常情况:子类方法在运行时抛出父类方法没有抛出的异常,这会导致基于父类编写的代码无法正常工作。
  • 参数范围改变:如果父类的方法接受的参数在子类中被限制为更小的范围,也会违反里氏替换原则。例如,父类方法可以接受任意正整数,但子类限制只能接受大于0的数字。

示例

假设有一个父类 Bird,以及其子类 Penguin。根据里氏替换原则,Penguin 应该可以替代 Bird,但是由于企鹅不能飞,如果子类 Penguin 修改了父类的 fly 方法(使得它抛出异常或实现一个无效的操作),则违反了里氏替换原则。

cpp 复制代码
class Bird {
public:
    virtual void fly() {
        // 父类的飞行方法
        std::cout << "I can fly!" << std::endl;
    }
};

class Penguin : public Bird {
public:
    void fly() override {
        // 企鹅不能飞,可能会导致错误或不合逻辑的行为
        std::cout << "I can't fly!" << std::endl;
    }
};

在上面的例子中,Penguin 类的 fly 方法可能导致父类 Birdfly 方法的行为发生变化,因此如果有其他代码依赖于 Bird 类的 fly 方法,那么在运行时替换为 Penguin 可能会导致不符合预期的行为,从而违反了里氏替换原则。

遵循里氏替换原则的设计:

为了遵循里氏替换原则,可以考虑将方法进行适当的重构,例如:

  • 接口分离 :通过接口(或抽象类)来区分具有不同行为的类,比如将飞行功能放入一个 Flyable 接口中,使得只有能飞的鸟类实现该接口,而不能飞的类(如企鹅)则不实现该接口。
cpp 复制代码
class Flyable {
public:
    virtual void fly() = 0;
};

class Bird {
public:
    virtual void move() = 0;  // 所有鸟类都有的行为
};

class Sparrow : public Bird, public Flyable {
public:
    void fly() override {
        std::cout << "I can fly!" << std::endl;
    }
    void move() override {
        std::cout << "I am moving!" << std::endl;
    }
};

class Penguin : public Bird {
public:
    void move() override {
        std::cout << "I am swimming!" << std::endl;
    }
};

总结:

里氏替换原则强调子类应能够完全替代父类,并且程序的行为应该保持一致。遵守该原则可以确保代码的可扩展性和可维护性,避免因子类的特殊行为导致父类期望功能的破坏。

相关推荐
Kerwin要坚持日更1 个月前
一文讲解Java中的重载、重写及里氏替换原则
java·里氏替换原则
诸神缄默不语1 个月前
里氏替换原则(Liskov Substitution Principle,LSP):面向对象设计的基本原则
开发语言·里氏替换原则
智驾1 个月前
SOLID原则学习,里氏替换原则
c++·里氏替换原则·solid
ke_wu2 个月前
常见设计原则
接口隔离原则·依赖倒置原则·里氏替换原则·开闭原则·迪米特法则·单一职责原则
Danileaf_Guo2 个月前
MPLS小实验:利用LDP动态建立LSP
里氏替换原则
向宇it2 个月前
【从零开始入门unity游戏开发之——C#篇26】C#面向对象动态多态——接口(Interface)、接口里氏替换原则、密封方法(`sealed` )
java·开发语言·unity·c#·游戏引擎·里氏替换原则
向宇it2 个月前
【从零开始入门unity游戏开发之——C#篇23】C#面向对象继承——`as`类型转化和`is`类型检查、向上转型和向下转型、里氏替换原则(LSP)
java·开发语言·unity·c#·游戏引擎·里氏替换原则
Danileaf_Guo2 个月前
MPLS小实验:静态建立LSP
网络·里氏替换原则
huaqianzkh3 个月前
里氏替换原则:Java面向对象设计的基石
java·设计模式·里氏替换原则