关于 LSP 的讨论有很多,但所有讨论似乎都过于模糊。
AFAIK,LSP 指出,要正确覆盖(而不是重载)子类中的父类(super class)方法,应确保子方法:
- 不会产生父方法在任何情况下都不会引发的新型异常
- 与父方法具有相同的签名(对于强类型语言)
- 与签名具有相同的语义
- 返回相同类型的值
- 返回相同语义的值
通过语义含义
我的意思是,如果基类方法意味着它返回int
并且这个int
意味着美元或欧元,那么重载方法还应该暗示返回值是美元或欧元,并且即使在一种情况下返回“RUB”也会违反 LSP。
但是如果我的基类看起来像这样(示例是 Python 中的)怎么办:
class A:
func(x: int) -> int
return x*2
class B(A):
func(x: int, y: string) -> int
return x*y
所以我的问题中有两个子问题:
- 术语
契约(Contract)
在更实际的意义上意味着什么?它与interface
同义吗? - 使用基类中不存在的签名(参数列表的一部分)进行重载是否会违反 LSP?
最佳答案
答案取决于语言。
在典型的 stronly 类型的 OO 语言中,如 Java、C++、C# 等,当您编写像 a.func(b,c)
这样的方法调用时,实际要调用的方法就确定了基于方法名称、接收类型(本例中为 a
类型)以及参数的数量和类型。
在这样的语言中,具有不同数量参数或不同类型参数的方法是完全不同的方法。拥有不同数量的参数就像拥有不同的名称一样。当您“重载”一个方法时,就像使用不同名称创建一个方法一样,因此您不会通过重载基类中的方法来违反 LSP。
不过,您的问题似乎与 python 有关,并且在典型的动态类型语言(如 python、JavaScript 等)中,当您编写像 a.func(b,c)
这样的方法调用时,仅按名称查找要调用的方法(在与接收对象关联的表中查找)。在这样的语言中,不存在方法或函数的重载。
在您的示例中,您使用双参数函数覆盖 func
的单参数定义。这意味着派生类的使用者无法再使用一个参数调用 func
,这确实是一种 LSP 违规。
关于python - 重载(而不是重写)是否违反了里氏替换原则?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61950209/