我想了解 Liskov 替换原则。但我无法确定 Liskov 替换原则与正常继承有何不同。 下面的代码是关于普通继承的。我应该如何处理下面的代码才能说我的代码遵循 Liskov 替换原则
public class ClassA
{
public virtual void MethodA()
{
Console.WriteLine("-----------------ClassA.MethodA---------------------");
}
public virtual void MethodB()
{
Console.WriteLine("-----------------ClassA.MethodB---------------------");
}
}
public class ClassB: ClassA
{
public override void MethodA()
{
Console.WriteLine("-----------------ClassB override ClassA.MethodA---------------------");
}
}
最佳答案
这是一个常见的定义:
The Liskov Substitution Principle (LSP): functions that use pointers to base classes must be able to use objects of derived classes without knowing it.
这里有一个更严谨的解释:
https://en.wikipedia.org/wiki/Liskov_substitution_principle
..Liskov 替换原则 (LSP) 是子类型关系的特定定义,称为(强)行为子类型,最初由 Barbara Liskov 在 1987 年题为数据抽象和层次结构的 session 主题演讲中引入。它是一种语义关系,而不仅仅是句法关系,因为它旨在保证层次结构中类型(尤其是对象类型)的语义互操作性。 Barbara Liskov 和 Jeannette Wing 在 1994 年的一篇论文中简要描述了该原理如下:
子类型要求:
设 ϕ ( x ) 是关于类型 T 的对象 x 的可证明属性。
那么对于类型 S 的对象 y 来说 ϕ ( y ) 应该为真,其中 S 是 T 的子类型。
Liskov 原则对更新的面向对象编程语言中采用的签名施加了一些标准要求(通常在类级别而不是类型级别;请参阅名义与结构子类型以了解区别):
- 子类型中方法参数的逆变。
- 子类型中返回类型的协方差。
- 子类型的方法不应抛出新异常,除非这些异常本身是父类(super class)型方法抛出的异常的子类型。
除了签名要求外,子类型还必须满足一些行为条件。这些在类似于契约设计方法的术语中进行了详细说明,从而导致对契约如何与继承交互的一些限制:
- 不能在子类型中加强先决条件。
- 不能在子类型中弱化后置条件。
- 父类(super class)型的不变量必须保留在子类型中。
- 历史约束(“历史规则”)。对象被认为只能通过它们的方法(封装)进行修改。因为子类型可能会引入父类(super class)型中不存在的方法,所以这些方法的引入可能会允许子类型中的状态更改,而这在父类(super class)型中是不允许的。历史约束禁止这样做。
问:你的例子符合吗?
答:我不这么认为。因为 A.MethodA() 在语义上与 B.MethodA() “不同”。 B 类未通过 The Duck Test .
我提出这个反例:
public class ClassA {
public virtual void MethodA() {
Console.WriteLine("ClassA.MethodA");
}
public virtual void MethodB(){
Console.WriteLine("ClassA.MethodB");
}
}
public class ClassC: ClassA {
public void MethodC() {
Console.WriteLine("ClassC.MethodC");
}
}
这也是为什么 LSP 不“等同于”继承的一个很好的例子。
关于c# - Liskov 替换原则与普通继承有何不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58897704/