【里氏替换原则 - 六大设计原则 - 设计模式】

353 阅读3分钟

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

定义:如果S是T的子类型,对于S类型的任意对象,如果将他们看作是T类型的对象,则对象的行为也理应与期望的行为一致。

子类对象能够替换程序中父类对象出现的任何地方,并且保证原来程序的逻辑行为不变及正确性不被破坏

通俗解释

如何理解里氏替换原则?

首先要明白两个问题?

  • 什么是替换?
  • 什么是与期望行为一致的替换?
什么是替换?

替换的前提是面向对象语言支持的多态特性,同一个行为具有多个不同表现形式或形态的能力。

什么是与期望行为一致的替换?

在不了解派生类的情况下,仅通过接口或基类的方法,即可清楚的知道方法的行为,而不管哪种派生类的实现,都与接口或基类方法的期望行为一致。

不需要关心是哪个类对接口进行了实现,因为不管底层如何实现,最终的结果都会符合接口中关于方法的描述(也就是与接口中方法的期望行为一致). 或者说接口或基类的方法是一种契约,使用方按照这个契约来使用,派生类也按照这个契约来实现。这就是与期望行为一致的替换

场景示例

里氏替换原则要求我们在编码时使用基类或接口去定义对象变量,使用时可以由具体实现对象进行赋值,实现变化的多样性,完成代码对修改的封闭,扩展的开放。 比如在一个app中,实现一个Theme功能,定义接口 ThemeInterface, 此接口有一个属性,有两个实现类,分别是白色主题(WhiteTheme),黑色主题(BlackTheme)

截屏2023-01-09 22.37.48.png

protocol ThemeInterface {
    var primaryColor: UIColor { get }
}

struct WhiteTheme: ThemeInterface {
    var primaryColor: UIColor {
        return .red
    }

}

struct BlackTheme: ThemeInterface {
    var primaryColor: UIColor {
        return .orange
    }

}

截屏2023-01-09 22.44.43.png

调用代码

struct App {
    private var theme: ThemeInterface
    init(theme: ThemeInterface) {
        self.theme = theme
    }

    func applyColor() {
        print("theme.primaryColor \(theme.primaryColor)")
    }

}

App 类中代码使用了接口定义对象变量,这个对象变量可以是实现了ThemeInterface接口的WhiteTheme、BlackTheme任意一个。

虽然从定义描述和代码实现上来看,多态和里氏替换有点类似,但它们关注的角度是不一样的。多态是面向对象编程的一大特性,也是面向对象编程语言的一种语法,它是一种代码实现的思路。而里氏替换是一种设计原则,用来指导继承关系中子类该如何设计,子类的设计要保证在替换父类的时候,不改变原有程序的逻辑及不破坏原有程序的正确性

里氏替换原则和依赖倒置原则,构成了面向接口编程的基础,正因为里氏替换原则,才使得程序呈现多样性。

LiskovSubsitutionPrinciple