Difference between the IS-A and Liskov Substitution Principle?
我只是想知道IS-A(UML术语和OOP)和Liskov替换原则(LSP)之间是否存在差异?
实际上,他们都在谈论遗产。那么,实践中的主要区别是什么呢?
两个术语最后都描述了相同的"概念"。
Liskov替换原理告诉你:当B类(base)和C类(child)的某个对象的每一个用法都是正确的时,B类(base)和C类(child)之间的继承关系是正确的。可以用C类型的对象替换。
这意味着:B定义了一个API和一个公共契约——C也必须维护这些属性!
is-a等于同样的东西:c的某个物体也是b。
区别在于:LSP提供了您可以检查的精确规则。而IS-A更像是一种"观察"或意向表达。比如:你表示你希望C班是B班。
换句话说:当您不知道如何正确地使用继承时,IS-A并不能帮助您编写正确的代码。而LSP清楚地告诉你:
1 2 | class Base { int foo(); } class Child extends Base { @Override double foo(); } |
无效。根据lsp,只能扩大方法参数,并限制返回值。
1 | int iValue = someBase.foo(); |
不能替换为
1 | int iValue = someChild.foo(); |
因为
最后一个想法是:很多人认为C是-A是B,这和写下
C IS-A B要求"C延伸B"以上。要真正有效,必须坚持LSP!
IS-A/HAS-A是关于是否使用继承。激光探测仪是一种激光器,还是应该有一个激光场?如果您以某种方式使用继承,那么lsp是一个需要注意的特定问题。
继承的好用法是动物a1;指向猫或狗,使用A1.速度()(*)。LSP说猫和狗的速度功能需要使用相同的单位。同样,A1.setweight对于猫不能允许负权重,但是狗将其更改为0。当您可以调用任意一个函数时,lsp是关于一致性的。如果你已经知道动物a1的话,事实上这很明显;诡计,这很难。
相反,假设你有独立的猫和狗。如果真的速度是不同的,猫用公制,狗用英语。如果猫和狗是从动物身上继承下来的,但是你从来没有用过"a1=猫或狗"的伎俩,那它还是可以的。c1.speed()是公制的,d1.speed()显然是每小时英里数。但如果你有功能动画(动物A1),你就有问题。
区别也在于音调。IS-A/HAS-A对于刚起步的人来说是一个简单的建议。LSP是一篇30年前为博士写的论文,它所使用的方程式是针对研究生的COM科学专业的。它使用了前后条件,这是当时常见的、众所周知的术语。""替换"是一个很好的数学术语,但今天我们只说"将指向任何子类的基类"。
(*)更详细地说:我们有超类动物,以及猫和狗的子类。动物有一个存根速度功能,猫和狗都会覆盖它。a1.speed()查找正确的。一个真正的例子是一系列动物,它们真的养着猫和狗。或具有动物输入的函数,期望有猫或狗。
(同样的*)通常基类是抽象的-我们永远不会创建动物对象。但如果我们有一个烤面包机超类和一个妄想烤面包机子类,技巧是相同的。任何带着烤面包机的东西都可能带着任何"是的"烤面包机。