来自Wikipedia,
Liskov的行为亚型概念定义了一个概念 对象的可替代性;也就是说,如果S是T的子类型,那么 程序中类型T的对象可以用类型S的对象替换 不改变该程序的任何所需属性(例如 正确性)。
假设以下类层次结构:
AnimalWithFur
。它有一个只读属性furColor
,在后续版本中被覆盖。Cat
,它会覆盖furColor
并返回灰色。Tiger
,它会覆盖furColor
并返回条纹。然后我们声明一个参数类型为Cat
的方法(不 AnimalWithFur
)。
向该方法发送Tiger
实例是否违反了SOLID中的 L ?
答案 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
在您的意义上,Tiger
是Cats family.
之一。从代码的角度来看,覆盖和覆盖是不好的设计完全替换父类的行为,这实际上是liskov替换违规 - 你的Cat
类意味着定义的猫有一些具体的颜色,应用程序希望分别使用它,但你用不一致的类型覆盖它并更改行为。
如果您要正确描述类型层次结构,那么您将使用抽象类型Cat
而不实现furColor,类型Tiger
和HomeCat
,但HomeCat
可能有不同的颜色,不是?
如果你想要LS违规的简单例子,例如:
您正在使用自定义实现扩展List
接口,返回大小始终为10,但内部对象的数量不同。每个普通的应用程序都希望使用for语句使用list,但是由于你破坏了LS原则,它会有不可预测的行为,而List对象的行为并不像预期的那样。