当前位置: 首页 > 知识库问答 >
问题:

这是对利斯科夫替代原理的正确理解吗

萧明贤
2023-03-14

这是在一次采访中问我的。

我回答他说,对于相同的输入集,父母和孩子都应该产生相同的输出集。如果子节点想要扩展父节点的功能,它应该只在父节点支持范围之外的新输入上执行。这样,孩子将维持其父母签订的合同。

我给他举了一个例子,一个api可能正在使用这样的父级

if(parent.getOutput(10) == 5){/*do something */}

如果这个孩子在这里产生了不同的输出,那么这个孩子就违反了它的父母签订的合同。

他对我的回答不满意,并告诉我这是简单的压倒一切,不违反LSP。所以,我只是想确认一下,我的理解是否正确。

共有1个答案

吕嘉赐
2023-03-14

不,这是不正确的。

Liskov替换原则的要点是,根据相关合同,子类应该能够以与父类相同的方式使用。它不需要为相同的输入生成相同的输出。

在不可避免的动物主题中,下面是一个示例,其中方法为相同的输入返回不同的输出:

class Dog {
  String getNoise() {
    return "WOOF WOOF!!!"
  }
}

class FrenchBulldog extends Dog {
  String getNoise() {
    return "mrfff!"
  }
}

法国斗牛犬可以在任何上下文中代表任何,行为方式相同,因此不违反LSP。

如果您改为创建如下内容:

class Hotdog extends Dog implements Edible {
  String getNoise() {
    throw new NotImplementedException("I am actually a sausage");
  }
  String eat() {
    return "Delicious";
  }
}

然后它就不能再代替狗了。与Dogs和FrenchBulldogs完美配合的代码不再以应有的方式工作。无论狗狗发出什么样的噪音,任何一个狗美容师或犬舍都知道该做什么,但是如果你带了热狗,他们会非常困惑。这违反了LSP。

 类似资料:
  • 我认为是这样的,因为子类在被替换时的行为不像基类,而且它抛出了一个RuntimeException? 我不完全确定,我想知道我的假设是否正确

  • 以下代码是否直接违反了Liskov替换原则: 子类不应破坏父类的类型定义。 结果如下: 致命错误:b::baz(Foo $foo)的声明必须与a::baz(Baz $baz)兼容

  • 有一个很好的例子,在圆-椭圆问题中违反了Liskov替换原理。 下面是一个流行的SO答案的措辞(尽管是矩形和正方形): 在数学中,是一个。实际上,它是矩形的特化。“is a”使您希望使用继承来对此进行建模。但是,如果在代码中使派生自,那么应该可以在任何需要的地方使用。这导致了一些奇怪的行为。 想象一下,您的矩形基类上有和方法;这似乎完全符合逻辑。但是,如果矩形引用指向,则和没有意义,因为设置一个将

  • 我试图通过反复阅读维基百科条目来确定我对上述原则的理解。 撇开仍然让我悲伤的协变和逆变的概念不谈,wikipedia还提到超类型的不变量必须保留在子类型和历史约束或历史规则中。基于最后两个概念,我提出了一个小例子: 所以我的问题是:基于上述两个概念,我用这个例子是否违反了原则?若否,原因为何? 事先非常感谢。

  • 现在,让我们来看看“燃料”类: 以上是完成的所有抽象类,现在让我们看看具体的实现。首先,fuel的两个具体实现,包括一些贫血接口,以便我们可以正确地键入-提示/嗅探它们: 最后,我们有了车辆的具体实现,它确保使用正确的燃料类型(接口)为特定的车辆类别加油,如果不兼容则抛出异常: null

  • 我正在详细学习LSP,我确实理解为什么强化先决条件违反了这一原则(使用来自http://www.ckode.dk/programming/solid-principles-part-3-liskovs-substitution-principle/#contravariance): 在这里,我清楚地看到,对于基类有效的东西对于它的派生类将失败。换句话说,在不改变行为的情况下,我无法用基类的导数替换