software-design - 打破里氏替换原则
问题描述
我有以下代码
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
和函数的结果是任意实数。
这里是否违反了里氏替换原则?
提前致谢。
解决方案
假设您想在程序中使用 B 作为 A 的子类型:
是的,您的代码显然违反了 LSK。
为什么?
参数应该是逆变的。
这意味着什么?
Liskov 原则保证,如果您的子类型 B 被基类型 A 替换,您的程序的行为不会改变。
或者更准确地说(Barbara Liskov,1987 年):
“如果对于类型 B 的每个对象 o1 都有一个类型 A 的对象 o2 ,
那么对于以 A 定义的所有程序 P ,
当 o1 替换 o2 时 P 的行为不变,则 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
如果您的程序将用基类替换子类,则您的程序对于 foo 关于值 <= 0 的行为不会像预期的那样。
编辑:虽然您在两个 foo 方法上都使用 double 作为参数的类型,但我假设您通过检查值及其范围来保护您的方法。这将导致描述的失败,类似于示例。
PS:是的,这取决于您为 foo 定义的合同。假设你想使用 B 作为 A 的子类型,那么它违反了 LSK。否则它只是一个方法覆盖。
推荐阅读
- spring-boot - 如何使用 Spring Boot 2 和 WebFlux 测试 @Controller
- angular - 如何从类型脚本触发 html 方法
- airflow - 如何使用 Airflow 在 Python 函数中触发运算符?
- c# - C# async:等待后我们是否需要锁定才能共享资源?
- python - 将函数应用于多索引数据帧
- css - 像 CSS 中的弹性项目一样收缩网格项目
- javascript - 如果语句使用 UserID?
- python - python install scrapy - 失败,错误代码 1
- python - (Step Functions Activity Worker)在 boto 中处理长轮询超时的最佳实践?
- java - 将嵌套键表示为 java 中的类