里氏替換原則

里式替換原則描述:

子類別應該可以替換父類並且行為不會受到影響。

在原本的里式替換原則之中,如果子類別無法替換父類別,就會出現程式上的錯誤。子類別必須完全替代父類別,並不會影響原有的程式邏輯。里氏替換原則適用於繼承和介面的應用,藉此實現程式碼的可擴展性和重用性。

最常見的例子是長方形與正方形:

Rectangle.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

public class Rectangle
{
public int Width { get; set; }

public int Height { get; set; }

public Rectangle(int width, int height)
{
Width = width;
Height = height;
}

public int CalculateArea()
{
return Width * Height;
}
}

Square.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Square: Rectangle
{
public Square(int width, int height) : base(width, height)
{
if (width != height)
{
throw new ArgumentOutOfRangeException(nameof(width));
}

this.Height = height;
this.Width = width;
}
}

原本客戶端程式碼如下:

1
2
3
// 在使用上,造成無法替換的問題
Rectangle rectangle = new Rectangle(4, 5);
var rectangleArea = rectangle.Area();

如果抽換成Square.cs:

1
2
3
// 在使用上,造成無法替換的問題
Rectangle rectangle = new Square(4, 5);
var rectangleArea = rectangle.Area();

總結

里氏替換原則(Liskov Substitution Principle, LSP)是指子類別應該能夠完全替代父類別而不會對程式造成錯誤。

符合 LSP 的設計原則包括子類別必須完全實現父類別的所有方法,並且不能新增或刪除父類別的任何方法;子類別的方法的前置條件不能比父類別更嚴格,後置條件不能比父類別更寬鬆等。

在架構層次上,LSP
的目的是減少系統中各個元件之間的相互依賴性,提高系統的靈活性和可擴展性。這需要通過抽象化和封裝等技術,將系統中的各個元件隔離開來,使得各個元件可以獨立地進行修改和擴展,而不會對其他元件造成影響。在實踐中,可以通過設計合適的接口和抽象類別,來實現
LSP。