gpt4 book ai didi

oop - 里氏原理中的论证逆变如何发挥作用?

转载 作者:行者123 更新时间:2023-12-05 00:21:19 26 4
gpt4 key购买 nike

里氏替换原则的基本点是父类(super class)可以被遵循相同契约(行为)的子类替换。或者正如 Martin Fowler 所说:“使用基类指针或引用的函数必须能够在不知情的情况下使用派生类的对象。”

参数逆变被提到是 LSP 的一部分,但我似乎无法理解它为什么以及如何工作。即,在子类中,重写方法可以接受更广泛的(派生较少的参数)。

像这样:

class Base
{
int GetLenght(string s)
{
return s.lenght;
}
}
class Derived: Base
{
override int GetLenght(object s)
{
?? I cannot return any lenght of an object..
}
}

这怎么可能行得通?我的意思是,如果衍生较少的论点不具有我需要的属性,我如何遵守契约(Contract)?

PS:我确实知道大多数面向对象语言不支持这一点,我只是好奇。

最佳答案

Argument contravariance is mentioned to be a part of LSP but I cannot seem to understand why and how it can work. I.e., in a subclass, the overriding method could accept wider (less derived argument).

首先,让我们确保我们已经定义了我们的术语。

“协方差”是关系和变换的属性。。具体来说,它是在特定转换上维持特定关系的属性。 “逆变”与协方差相同,只不过它是在变换中维持但反转特定关系。

举个例子吧。我手头有一个类型,我希望按照规则 T 将其转换为不同的类型转换为Func<T> 。我在类型之间有一个关系:“X类型的表达式可以分配给Y类型的变量”例如,Giraffe类型的表达式可以分配给 Animal 类型的变量。该变换是协变的,因为在整个变换过程中保留了关系:Func<Giraffe> 类型的表达式可以分配给 Func<Animal> 类型的变量.

转型T转换为Action<T>反转关系:Action<Animal>可以分配给Action<Giraffe> .

但是TAction<T>是委托(delegate)所表示的方法的形参类型。正如您所看到的,我们可以在形式参数类型上实现逆变。

这对于方法重写意味着什么?当你说

class B 
{
public virtual void M(Giraffe g) { b body }
}
class D : B
{
public override void M(Giraffe g) { d body }
}

这在逻辑上是相同的

class B 
{
protected Action<Giraffe> a = g => { b body };
public void M(Giraffe g) { this.a(g); }
}
class D : B
{
public D() {
this.a = g => { d body };
}
}

对吗?我们用

替换 D 的构造函数是完全合法的
   this.a = some Action<Animal>

对吗?然而,C#——以及大多数其他面向对象语言,但不是全部——不允许

class D : B 
{
public override void M(Animal a) { d body }
}

尽管逻辑上它的工作原理与通用委托(delegate)逆变工作原理一样。这只是一个可以实现但从未实现的功能,因为还有很多更好的事情要做。

How could this ever work? I mean, how could I comply with the contract if the less derived argument does not have the properties I need?

如果你不能,那么你就不会,不是吗?

假设我需要

int CompareHeights(Giraffe g1, Giraffe g2)

我可以用一种方法来替换它,这看起来是不是太难以置信了

int CompareHeights(Animal a1, Animal a2)

?我需要一个比较长颈鹿高度的方法,我有一个比较动物高度的方法,所以我完成了,对吧?

假设我需要

void Paint(Circle, Color)

我可以用一种方法替换它,这似乎难以置信

void Paint(Shape, Color)

?这对我来说似乎是合理的。我需要一个绘制圆形的方法,我有一个绘制任何形状的方法,所以我完成了。

如果我需要

int GetLength(string)

我有

int GetLength(IEnumerable)

那我就好了。我需要一个获取字符串长度的方法,该字符串是一个字符序列。我有一个方法可以获取任何序列的长度,所以我很好。

关于oop - 里氏原理中的论证逆变如何发挥作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49834460/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com