# 里氏替换原则（Liskov Substitution Principle）

Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

Barbara Liskov 在 1988 年提出了这一原则：

What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.

```1 void DrawShape(const Shape& s)
2 {
3     if (typeid(s) == typeid(Square))
4         DrawSquare(static_cast<Square&>(s));
5     else if (typeid(s) == typeid(Circle))
6         DrawCircle(static_cast<Circle&>(s));
7 }    ```

``` 1   public class Rectangle
2   {
3     private double _width;
4     private double _height;
5
6     public void SetWidth(double w) { _width = w; }
7     public void SetHeight(double w) { _height = w; }
8     public double GetWidth() { return _width; }
9     public double GetHeight() { return _height; }
10   }```

``` 1   public class Square : Rectangle
2   {
3     public void SetWidth(double w)
4     {
5       base.SetWidth(w);
6       base.SetHeight(w);
7     }
8     public void SetHeight(double w)
9     {
10       base.SetWidth(w);
11       base.SetHeight(w);
12     }
13   }```

```1   public void TestCase1()
2   {
3     Square s = new Square();
4     s.SetWidth(1); // Fortunately sets the height to 1 too.
5     s.SetHeight(2); // sets width and heigt to 2, good thing.
6   }```

```1   void f(Rectangle r)
2   {
3     r.SetWidth(32); // calls Rectangle::SetWidth
4   }```

``` 1   public class Rectangle
2   {
3     private double _width;
4     private double _height;
5
6     public virtual void SetWidth(double w) { _width = w; }
7     public virtual void SetHeight(double w) { _height = w; }
8     public double GetWidth() { return _width; }
9     public double GetHeight() { return _height; }
10   }
11
12   public class Square : Rectangle
13   {
14     public override void SetWidth(double w)
15     {
16       base.SetWidth(w);
17       base.SetHeight(w);
18     }
19     public override void SetHeight(double w)
20     {
21       base.SetWidth(w);
22       base.SetHeight(w);
23     }
24   }```

（注：自洽性即逻辑自洽性和概念、观点等的前后一贯性。首先是指建构一个科学理论的若干个基本假设之间，基本假设和由这些基本假设逻辑地导出的一系列结论之间，各个结论之间必须是相容的，不相互矛盾的。逻辑自洽性也要求构建理论过程中的所有逻辑推理和数学演算正确无误。逻辑自洽性是一个理论能够成立的必备条件。）

```1   void g(Rectangle r)
2   {
3     r.SetWidth(5);
4     r.SetHeight(4);
5     Assert.AreEqual(r.GetWidth() * r.GetHeight(), 20);
6   }```

LSP 原则使我们清楚了 OOD 中 is-a 关系是与行为有关的。不是内在的私有的行为，而是外在的公共的行为，是使用者依赖的行为。例如，上述函数 g 的作者依赖了一个基本事实，那就是 Rectangle 的 Width 和 Height 彼此之间的变化是无依赖关系的。而这种无依赖的关系就是一种外在的公共的行为，并且其他程序员有可能也会这么想。

Bertrand Meyer 在 1988 年阐述了 LSP 原则与契约式设计之间的关系。使用契约式设计，类中的方法需要声明前置条件和后置条件。前置条件为真，则方法才能被执行。而在方法调用完成之前，方法本身将确保后置条件也成立。

`1 Contract.Ensures((_width == w) && (_height == Contract.OldValue<double>(_height)));`

…when redefining a routine [in a derivative], you may only replace its precondition by a weaker one, and its postcondition by a stronger one.

 SRP 单一职责原则 Single Responsibility Principle OCP 开放封闭原则 Open Closed Principle LSP 里氏替换原则 Liskov Substitution Principle ISP 接口隔离原则 Interface Segregation Principle DIP 依赖倒置原则 Dependency Inversion Principle

## 里氏替换原则（Liskov Substitution Principle） LSP

using System; using System.Collections.Generic; using System.Text; namespace LiskovSubstitutionPrinciple { //里氏替换原则(Liskov Substitution Principle) LSP //If for each object o1 of type S there is an object o2 of type T such that for all programs P defi