打破李斯科夫替代原则

时间:2019-04-10 07:06:29

标签: software-design solid-principles liskov-substitution-principle

我有以下代码

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的输入和函数的结果是任何实数。

这里是否违反了利斯科夫换人原则?

提前谢谢。

2 个答案:

答案 0 :(得分: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 您的子类B foo期望参数值0 如果您的程序将基类替换为子类,则对于值<= 0的foo,您的程序将无法达到预期的效果。

编辑:尽管您在两个foo方法上都将double类型用作参数,但我假设您通过检查值及其作用域来保护自己的方法。类似于示例,这将导致所描述的失败。

P.S .:是的,这取决于您为foo定义的合同。假定您要使用B作为A的子类型,则它违反了LSK。否则,它只是方法的重载。

答案 1 :(得分:0)

实际上,您的重写函数违反了基本函数的约定,因此Liskov原理在此并不是真正有用。但是,如果您在基本函数中添加“处理模式”之类的参数,则L原理可以正常工作(对于所有旧处理情况,被覆盖的函数都会调用基本函数)。