我最近一直在深入研究一些SOLID设计原则,我从一个来源获得的一些信息最初对我有意义,但基于我能够找到的严格定义LSP,似乎信息可能不正确。信息具体是:
1)在重写方法上没有回调到super()会违反LSP(或者至少会打开你的违规行为),因为基类的行为可能会在某些时候发生变化,而你的子类可能会丢失行为导致子类不再可替代父类。这似乎对我有意义,但是如果有人可以详细说明/给出一些关于什么时候不适合不回电话的信息那就太棒了。
2)子类的限制不应低于父类。示例是:如果您的父类只接受正整数,那么您创建一个接受正负int的子类。因此,孩子应该在父母的位置上工作正常,但在这种情况下,孩子不能委托给超级。
我认为这是有道理的,但LSP上的信息似乎反过来说:孩子可以强化的前提条件。两者似乎都对我有意义,但利斯科夫只表示前提条件不能得到加强,后置条件不能被削弱。有人可以帮我启发吗?
答案 0 :(得分:1)
1)案例,如果不适合不回电话
通常(但并非总是)这种情况意味着类层次结构设计出了问题。
如果子方法接受正确的输入类型并返回正确的输出类型,则不调用超类实现不会违反LSP。 它只表明问题的可能性。
当你不调用超级方法时,这是一个绝对有效的例子:
class Animal
void eat(Food food)
// Eat the food
class Cat extends Animal
void meow()
// Say meow
class AnimalOwner
Animal findAPet()
return new Animal()
class CatOwner
// we can return the subclass of Animal here
Cat findAPet()
return new Cat() // We don't need to use the parent implementation
此处CatOwner::findAPet()
返回Cat
(Animal
子类),这在LSP方面有效,我们不会调用父实现。
请注意,调用父实施并不能保证您不会遇到与不打电话时相同的问题。
考虑这个例子:
class Child
Output doSomething()
parent = super::doSomething()
if parent->isNotGood():
return new OutputSubclass() // We called super, but we return
// something different, might be not safe
else:
return parent // We called super and return
// the same value, safe
2)"在子类型中不能强化前提条件"。这也意味着前提条件(与输入参数相关的期望)可以保持不变或被削弱。 在你提到的例子中,前提条件实际上被削弱了,所以没有冲突:
Parent::doSomething(PositiveInteger value) // Only positive integers
Child::doSomething(Integer value) // Positive or negative integers,
// pre-condition is weaker
// (covers wider area of values)
第一句话不完全正确:"子类的限制性不应低于父级"。 当我们讨论前置条件(输入参数)时,子类可以减少限制,这就是示例中所示。
答案 1 :(得分:0)
Liskov替换原则要求您可以在期望基类型时使用子类型。为此,您必须遵守基本类型的合同。对于具有方法f,前提条件Pre,postcondition Post和不变I的基类B,这意味着
我会考虑显式调用基类实现代码气味(构造函数除外)。使用te,plate method pattern(或non-virtual interface in C++)来强制执行基类合约要好得多。在Python中,这看起来像:
class Base:
def publicMethod(self, x):
// do something
self.templateMethod(x)
// do something else
def templateMethod(self, x):
// has to be overriden by sub-classes
// it provides extension hooks, but
// publicMethod ensures that the overall
// functionality is correct