我是否正确理解在对象可以自我检查的语言(如鸭式语言中常见的语言)中不能遵守《里斯科夫替代原理》?
例如,在Ruby中,如果一个类B
从一个类继承A
,然后为每个对象x
的A
,x.class
是要回报A
的,但如果x
是一个对象B
,x.class
是不会返回A
。
这是LSP的声明:
令q(x)是关于类型T的对象x的可证明性质。那么,对于类型S的对象y,q(y)应该是可证明的,其中S是T的子类型。
以Ruby为例,
class T; end
class S < T; end
如属性q(x) =所示,以这种形式违反LSPx.class.name == 'T'
加成。如果答案是“是”(与内省不兼容的LSP),那么我的另一个问题是:是否存在某种修改后的“弱”形式的LSP,它可能适用于动态语言,可能在某些附加条件下并且仅具有特殊类型的性质。
更新。作为参考,这是我在网络上发现的另一种LSP公式:
使用指针或对基类的引用的函数必须能够使用派生类的对象,而无需了解它。
还有一个:
如果S是声明的T的子类型,则将S类型的对象视为T类型的对象,如果将它们视为T类型的对象,则它们的行为也应与预期的T类型的对象相同。
最后一个注释为:
请注意,LSP全部关于对象的预期行为。只有清楚知道对象的预期行为后,才能遵循LSP。
这似乎比最初的要弱,并且可能可以观察到,但是我希望看到它正式化,尤其要解释谁决定预期的行为是什么。
那么,LSP是否不是编程语言中的一对类的属性,而是祖先类满足的一对类以及给定的一组属性?实际上,这是否意味着要构造一个尊重LSP的子类(后代类),必须知道祖先类的所有可能用法?根据LSP,祖先类应该可以用任何后代类替换,对吗?
更新。 我已经接受了答案,但是我想添加一个来自Ruby的更具体的例子来说明这个问题。在Ruby中,每个类都是模块,从某种意义上来说,Class
类是类的后代Module
。然而:
class C; end
C.is_a?(Module) # => true
C.class # => Class
Class.superclass # => Module
module M; end
M.class # => Module
o = Object.new
o.extend(M) # ok
o.extend(C) # => TypeError: wrong argument type Class (expected Module)