Liskov替换原则违规

时间:2016-12-29 17:46:09

标签: oop solid-principles liskov-substitution-principle

来自Wikipedia

  

Liskov的行为亚型概念定义了一个概念   对象的可替代性;也就是说,如果S是T的子类型,那么   程序中类型T的对象可以用类型S的对象替换   不改变该程序的任何所需属性(例如   正确性)。

假设以下类层次结构:

  1. 基本抽象类 - AnimalWithFur。它有一个只读属性furColor,在后续版本中被覆盖。
  2. 基类的后继者 - Cat,它会覆盖furColor并返回灰色
  3. Cat的继任者 - Tiger,它会覆盖furColor并返回条纹
  4. 然后我们声明一个参数类型为Cat的方法( AnimalWithFur)。
    向该方法发送Tiger实例是否违反了SOLID中的 L

3 个答案:

答案 0 :(得分:4)

严格来说,是的。 Liskov的维基文章总结说:

  

" ...在 a 计划中...而不改变 计划"的任何理想属性

如果你回到Barbara Liskov的original paper,它的措辞字面上更加严格 3.3。 输入层次结构

  

如果对于类型S的每个对象o1,存在类型为T的对象o2,使得对于根据T定义的所有程序P,P 的行为不变当o1代替o2

(Empahsis mine)

因此,如果将Cat的实例替换为另一个执行不同操作的实例,即返回剥离而不是灰色,那么这是原始意义上的Liskov违规,因为可以轻松定义依赖于的程序颜色是灰色的,这里:

program(Cat c){
   println(c.furColor);
}

如果您使用Tiger代替Cat,该程序的行为将会改变

但是,以正常方式应用LSP,如果您没有添加额外的前置条件或后置条件,则不会违反。这是一个更实际,更少学术性的定义,因为人们接受当用另一个具体类型替换一个具体类型的实例时,意图改变程序的行为,同时保持该程序的期望属性。所以假定客户端代码可以像任何其他颜色一样处理剥离,并且#34;理想的"不需要灰色。程序的属性然后它不违反。

答案 1 :(得分:1)

简短回答:不一定。我没有说过你提供的信息。对我来说,关键是你不能说出想象的新方法应该做什么。

您可能会认为新方法中您需要的行为比类层次结构更重要。

执行此操作的一种方法是为传入的实例/参数中的新方法所需的行为定义接口。

然后,您可能希望传递给该方法的任何类都可以实现该接口,并且您可以分离继承层次结构的关注并转而关注行为的一致性。

答案 2 :(得分:1)

您的问题很好地描述了为什么要使用类组合而不是类继承。首先,您的代码不合逻辑 - Tiger不是Cat在您的意义上,TigerCats family.之一。从代码的角度来看,覆盖和覆盖是不好的设计完全替换父类的行为,这实际上是liskov替换违规 - 你的Cat类意味着定义的猫有一些具体的颜色,应用程序希望分别使用它,但你用不一致的类型覆盖它并更改行为。 如果您要正确描述类型层次结构,那么您将使用抽象类型Cat而不实现furColor,类型TigerHomeCat,但HomeCat可能有不同的颜色,不是?

如果你想要LS违规的简单例子,例如: 您正在使用自定义实现扩展List接口,返回大小始终为10,但内部对象的数量不同。每个普通的应用程序都希望使用for语句使用list,但是由于你破坏了LS原则,它会有不可预测的行为,而List对象的行为并不像预期的那样。