2016-12-29 89 views
2

如所述here里氏替换原则违反

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

假设,我们有下一个类层次结构:

  1. 的基础上,抽象类 - AnimalWithFur。它具有只读属性furColor,这应该在后继中被覆盖。
  2. 基类的后继者 - Cat,它覆盖了furColor并返回灰色。
  3. 猫的继任者 - 老虎,它覆盖furColor和收益剥离

然后,我们声明了一个方法,它有一个类型猫(不AnimalWithFur)的参数。向该方法发送Tiger实例会违反SOLID中的L原则吗?

回答

4

严格来说,是的。里氏的wiki文章总结说:

“......在一个程序......在不改变任何理想特性节目”

如果你去回到Barbara Liskov的original paper,它的字面上更严格在其措辞,3.3。 类型层次

如果S型的每一个对象O1有类型T的对象O2使得对于所有程序P IN的T来定义,P 的行为是不变当O1代替O2

(Empahsis矿)

所以,如果你与另一个实例,做不同的东西,即returnin取代Cat实例摹剥离不是灰色的,那么这是一个里氏违反原来的意义,因为一个程序可以很容易地定义依赖于颜色是灰色的,在这里:

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

该程序的行为可能会改变如果你通过它Tiger代替Cat

但是,如果您没有添加额外的前提条件或后置条件,那么以正常方式应用LSP并不违反。这是一个更实用,更不科学的定义,因为人们接受在用另一个实体替换一个具体类型的实例时打算改变程序的行为,同时保持该程序的理想属性。所以假设客户端代码可以像其他颜色一样处理剥离,并且灰色对于程序的“合意”属性不是必需的,那么它不会违反。

+0

重写参数类型为AnimalWithFur改变了什么? –

+0

不,因为属性furColour在AnimalWithFur上。而且你还在用一只老虎替代一只猫,因为我必须假设,如果你考虑LSP,你代替了,你只有两种具体类型;猫和老虎。 – weston

+0

甚至可能不关心实际定义的属性的位置,如果它改变了程序的理想属性,那么它就是LSP违例。 – weston

1

简答:不一定。我不会说你提供的信息。对我而言,关键在于你没有说出想象中的新方法应该做什么。

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

做到这一点的一种方法是为传入的实例/参数中新方法需要的行为定义一个接口。

然后,无论您想要传入该方法的哪个类都可以实现该接口,并且可以分开继承层次结构的关注点并转而关注行为的一致性。

1

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

如果你想有一个微不足道的例子,例如: 你正在扩展List接口与自定义实现,返回大小总是10,但与不同数量的对象内。每个正常的应用程序都希望使用for语句来处理列表,但由于您破坏了LS原则,并且List对象的行为并不像预期的那样,所以会出现不可预知的行为。

+0

我并不完全同意你关于类的层次结构,但即使有你的评论 - 我的代码仅仅是一个例子,它并没有被设计成最好的解决方案:)很容易理解和绘制与现有的并行,并使用广泛的例子,至于我。不过,我喜欢你关于作文的注意事项。好评 –

相关问题