python - 重载(而不是重写)是否违反了里氏替换原则?

标签 python oop design-patterns liskov-substitution-principle

关于 LSP 的讨论有很多,但所有讨论似乎都过于模糊。
AFAIK,LSP 指出,要正确覆盖(而不是重载)子类中的父类(super class)方法,应确保子方法:

  1. 不会产生父方法在任何情况下都不会引发的新型异常
  2. 与父方法具有相同的签名(对于强类型语言)
  3. 与签名具有相同的语义
  4. 返回相同类型的值
  5. 返回相同语义的值

通过语义含义我的意思是,如果基类方法意味着它返回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

所以我的问题中有两个子问题:

  1. 术语契约(Contract)在更实际的意义上意味着什么?它与interface同义吗?
  2. 使用基类中不存在的签名(参数列表的一部分)进行重载是否会违反 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/

相关文章:

python - 使用 python mechanize 和具有随机代理支持的 urllib2

python - 如何在基于外部查询的子查询中创建条件?

python - 为 sdist 生成文件

c# - OOP 约定 - 单函数方法

c++ - 错误 C2259 : 'class' : cannot instantiate abstract class

java - 设计模式——这是什么模式?

java - 一次实例化一堆类的正确方法

python - 防止双轴的网格线从原始轴绘制在艺术家之上

c++ - 如何初始化指向对象的动态指针数组?

java - 单例实例化创建多个对象