Python 重载(而非重写)是否违反了Liskov替代原则?
关于LSP的讨论有很多,但似乎都过于模糊。Python 重载(而非重写)是否违反了Liskov替代原则?,python,oop,design-patterns,liskov-substitution-principle,Python,Oop,Design Patterns,Liskov Substitution Principle,关于LSP的讨论有很多,但似乎都过于模糊。 首先,LSP指出,要正确地覆盖子类中的超类方法(而不是重载),应该确保子类方法: 不会产生在任何情况下都不会由父方法引发的新类型的异常 与父方法具有相同的签名(对于强类型语言) 具有与签名相同的语义 返回相同类型的值 返回具有相同语义的值 通过语义我的意思是,如果基类方法意味着它返回int,而这个int意味着美元或欧元,那么重载方法也应该意味着返回的值是美元或欧元,即使在一种情况下返回“RUB”也会违反LSP 但是,如果我的基类看起来像这样(示例是Py
首先,LSP指出,要正确地覆盖子类中的超类方法(而不是重载),应该确保子类方法:
语义
我的意思是,如果基类方法意味着它返回int
,而这个int
意味着美元或欧元,那么重载方法也应该意味着返回的值是美元或欧元,即使在一种情况下返回“RUB”也会违反LSP
但是,如果我的基类看起来像这样(示例是Python):
我的问题有两个子问题:
合同
是什么意思?与接口
是否一致在现实生活中,合同是甲、乙双方可以相互期望的,他们提供的保证。在编程中也是如此:
- 此方法接受什么范围的参数
- 你能从中期待什么样的行为
- in何时抛出错误
PS:如果你使用一个策略或命令,那么实现将是完全不同的事情。所以LSP在这里不适用。但他们仍然需要遵循母公司中描述的通用合同。要理解LSP的含义,口号“不要更多要求,不要更少承诺”帮助很大。重写方法不能要求更多的参数或更特定类型的参数(即,它们必须是逆变的)。它必须承诺返回与重写方法相同或更具体类型的值(即,它必须是协变的) 语义约束是重写方法必须在子类中执行与在超类中相同的操作。这种做同样事情的概念不容易形式化,并且取决于类本身的含义。但是,如果重写方法调用被重写的方法,这是语义一致性的有力标志
重载与LSP无关。这只是一个编译时技巧,允许不同的方法具有相同的名称。答案取决于语言
典型的java、C++、C等类的OO语言,在编写一个方法调用时,如“代码>A.FUNC(B,C)< /CODE >),根据方法名称确定接收的实际方法,以及接收类型(在这个例子中,<代码> A/COD>类型),以及参数的类型和类型。 在这样的语言中,具有不同数量参数或不同类型参数的方法是完全不同的方法。拥有不同数量的参数就像拥有不同的名称一样。当您“重载”一个方法时,这就像使用不同的名称创建一个方法,所以您不会因为重载基类中的方法而违反LSP
不过,您的问题似乎是关于python的,在python、JavaScript等典型的动态类型语言中,当您编写类似a.func(b,c)
的方法调用时,要调用的方法只按名称查找(在与接收对象关联的表中查找)。在这样的语言中,不存在方法或函数的重载
在您的示例中,您已使用双参数函数覆盖了
func
的单参数定义。这意味着派生类的使用者不能再使用一个参数调用func
,这确实是LSP冲突。契约与接口相同。它只是同一事物的另一个更合适的词。你是专门谈论Python,还是这种语言不可知?我看到您最初没有添加语言标记,但在@SergeyBerezovskiy添加python标记时没有恢复。究竟为什么是-1?感谢您的解释,我很感激
class A:
func(x: int) -> int
return x*2
class B(A):
func(x: int, y: string) -> int
return x*y