SOLID:C# 中的里氏替换原则 (LSP)
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
介绍
里氏替换原则(LSP)是面向对象设计中的一个基础概念,由芭芭拉·里氏于1987年提出。它指出:
"Objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program."
简而言之,派生类必须能够替代其基类,且不改变程序的预期行为。LSP 确保类层次结构的设计能够提高可重用性和可靠性。
LSP的关键方面
- 行为一致性:子类必须遵循其基类定义的行为。
- 无需担心:子类不应覆盖或削弱基类的任何功能。
- 契约:子类应遵守基类建立的“契约”(例如,前提条件和后置条件)。
违反 LSP 通常会导致代码脆弱,难以维护或扩展。
错误代码❌
public class Rectangle
{
public virtual double Width { get; set; }
public virtual double Height { get; set; }
public double GetArea() => Width * Height;
}
public class Square : Rectangle
{
public override double Width
{
set { base.Width = base.Height = value; }
}
public override double Height
{
set { base.Width = base.Height = value; }
}
}
public class LSPViolationDemo
{
public static void Main()
{
Rectangle rectangle = new Square(); // Substitution occurs here
rectangle.Width = 4;
rectangle.Height = 5; // Expecting Width=4 and Height=5 for a rectangle
Console.WriteLine($"Area: {rectangle.GetArea()}"); // Output: 25, not 20!
}
}
出什么问题了?❌
Square用正方形代替Rectangle矩形违背了预期。矩形可以有不同的宽度和高度,但正方形的边长必须相等。因此,GetArea在这种情况下,结果是错误的。
遵循 LSP:更佳设计 ✔
为了遵循 LSP 原则,应避免强制子类执行不兼容的行为。在这种情况下,将子类分离Rectangle到Square不同的层次结构中可以解决这个问题:
public abstract class Shape
{
public abstract double GetArea();
}
public class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public override double GetArea() => Width * Height;
}
public class Square : Shape
{
public double SideLength { get; set; }
public override double GetArea() => SideLength * SideLength;
}
public class LSPAdherenceDemo
{
public static void Main()
{
Shape rectangle = new Rectangle { Width = 4, Height = 5 };
Shape square = new Square { SideLength = 4 };
Console.WriteLine($"Rectangle Area: {rectangle.GetArea()}");
Console.WriteLine($"Square Area: {square.GetArea()}");
}
}
为什么这种方法有效?
- 两者
Rectangle都Square源自形状,但它们独立运作,遵循各自的特定行为。 - LSP得以保留,因为替换过程尊重了每个类的预期行为。
跟随LSP的好处
- 提高了代码复用性:子类可以与现有代码无缝协作。
- 易于测试:遵循 LSP 的代码具有可预测性,更容易测试。
- 增强维护性:类之间的清晰边界使调试和扩展功能变得简单。
结论
里氏替换原则对于创建健壮且灵活的面向对象设计至关重要。通过确保子类可以与其基类互换使用而不会导致意外行为,您可以构建更易于维护和扩展的系统。在设计类层次结构时,请始终问自己:“这个子类能否在不改变程序行为的情况下替换其基类?”
遵循 LSP 不仅能加强你对 SOLID 原则的遵循,还能为可扩展、可维护的软件解决方案奠定基础。祝你编码愉快!
欢迎在LinkedIn上与我联系,也欢迎查看我的GitHub代码库:
文章来源:https://dev.to/extinctsion/solid-the-liskov-substitution-principle-lsp-in-c-1hl9

