10.1.3 里氏替换原则
里氏替换原则( The Liskov Substitution Principle, LSP)关注的是怎样良好地使用继承。Liskov 于 1987 年提出了一个关于继承的原则“ Inheritance should ensure that any property provedabout supertype objects also holds for subtype objects.(继承必须确保父类所拥有的性质在子类中仍然成立。)”。也就是说,当一个子类的实例应该能够替换其父类的任何实例时,它们之间
才具有 is-A 关系。该原则被称为 The Liskov Substitution Principle——里氏替换原则。下面将用一个经典案例来做解释说明。
在我们的认知范围内,长方形的长度不等于宽度,正方形是长度等于宽度的长方形,正方形是一种特殊的长方形。但在实际编码过程中遇到的情况是怎样的呢?下面通过代码分析:
1. public class Rectangle
2. {
3. public virtual int Width { get; set; }
4. public virtual int Height{ get; set; }
5. public int Area()
6. {
7. return Width * Height;
8. }
9. }
10. public class Square : Rectangle
11. {
12. public override int Width
13. {
14. get
15. {
16. return base.Width;
17. }
18. set
19. {
20. base.Width = value;
21. base.Height = value;
22. }
23. }
24. public override int Height
25. {
26. get
27. {
28. return base.Height;
29. }
30. set
31. {
32. base.Height = value;
33. base.Width = value;
34. }
35. }
36. }
Square 继承 Rectangle。按照 LSP 原则,只要是父类出现的地方都可以用子类进行替换:
1. public static void TestMethod(Rectangle rec)
2. {
3. rec.Width = 10;
4. rec.Height = 15;
5. var area = rec.Area();
6. Assert.AreEqual(150, area);
7. }
那么可以将该方法中的 Rectangle rec 替换成 Square。下面试试:
1. public static void Main(string[] args)
2. {
3. Rectangle r = new Rectangle();
4. TestMethod(r);
5. Square s = new Square();
6. TestMethod(s);
7. }
运行后会出现异常“ NUnit.Framework.AssertionException”,这说明正方形是特殊的长方形违背了 LSP 原则。
所谓的对象是一组状态和一系列行为的组合。状态是对象的内在特性,行为是对象的外在特性。 LSP 原则所表述的是,同一个继承体系中的对象应该有共同的行为特征。我们在设计对象时是按照行为进行分类的,只有行为一致的对象才能抽象出一个类。在设置长方形的长度的时候,它的宽度保持不变;而设置宽度的时候,长度保持不变。正方形的行为是:设置正方形的长度的时候,宽度随之改变;设置宽度的时候,长度随之改变。所以,如果把这种行为加到基类长方形上的时候,就导致了正方形无法继承这种行为。若我们“强行”从长方形继承正方形,就会得到无法达到预期的结果。
10.1.4 接口隔离原则
接口隔离原则( Interface Segregation Princip