打破Liskov替代原则

问题描述 投票:1回答:2

我有以下代码

public class A 
{
      public double foo(double y) 
      {
             return real_value;
      }
}

其中foo方法-1 < y < 1的输入和函数的结果是大于零的实数。

然后我有继承class B继承class A并覆盖方法foo

public class B extends A 
{
      public override double foo(double y)
      {
         return real_value;
      }
}

其中foo方法0 < y < 1的输入和函数的结果是任何实数。

Liskov替换原则是否违反了?

提前致谢。

software-design solid-principles liskov-substitution-principle
2个回答
1
投票

假设您想在程序中使用B作为A的子类型: 是的,您的代码明显违反了LSK。

为什么? 争论应该是逆变的。

那是什么意思? Liskov Principle确保,如果子类型B被基类型A替换,则程序的行为不变。

或者更准确地说(Barbara Liskov,1987):

“如果对于类型B的每个对象o1,则存在类型A的对象o2 这样,对于按照A定义的所有程序P,P的行为不变 当o1代替o2时,则B是A“的子类型。

例如:

   class Duck               { void fly(int   height) {} }
   class RedheadDuck : Duck { void fly(long  height) {} }
   class RubberDuck : Duck  { void fly(short height) {} }

   class LSPDemo
   {
      public void Main()
      {
         Duck p;

         p = new Duck();
         p.fly(int.MaxValue); // Expected behaviour

         p = new RedheadDuck();
         p.fly(int.MaxValue); // OK   

         p = new RubberDuck();
         p.fly(int.MaxValue); // Fail 
      }
   }

=> the program behaves unchanged, if the argument is contravariant.
=> e.g. base type <= sub type
=> RubberDuck violates this principle, as it does not allow all values of the base type Duck

在您的代码中,基类A foo的类型将期望参数值-1 <y <1 你的子类B foo期望参数值0 <y <1 如果您的程序将使用基类替换子类,则对于值<= 0,您的程序将不会像foo那样表现出预期的行为。

编辑:虽然你在两个foo方法的参数上使用double作为类型,但我假设你通过检查值及其范围来保护你的方法。这将导致所描述的失败,类似于示例。

P.S。:是的,这取决于你为foo定义的合同。假设您想使用B作为A的子类型,那么它违反了LSK。否则它只是一种方法覆盖。


0
投票

实际上,你的重写函数违反了基函数的契约,所以Liskov原理在这里并没有用。但是,如果向基本函数添加“处理模式”之类的参数,则L原理可以正常工作(重写函数将为所有旧处理案例调用基函数)。

© www.soinside.com 2019 - 2024. All rights reserved.