问题标签 [liskov-substitution-principle]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
5 回答
2719 浏览

inheritance - 弱化前置条件和加强后置条件不也违反里氏替换原则吗?

子类型的实际前提条件是通过组合(使用逻辑OR基类型的前提条件和子类型的前提条件来创建的,这使得生成的前提条件 限制较少。

子类型的实际后置条件是通过组合(使用逻辑AND基本类型的置条件和子类型的后置条件来创建的,这使得生成的后置条件 更具限制性。

以下是加强前置条件削弱后置条件的示例,因此违反了 LSP(链接):

  1. 假设您的基类与成员 int 一起使用。现在您的子类型要求该 int 为正数。这是强化的先决条件,现在任何以前使用负整数都可以正常工作的代码都被破坏了。

  2. 同样,假设相同的场景,但用于保证成员在被调用后为正的基类。然后子类型改变行为以允许负整数。对对象起作用的代码(并假设后置条件是一个正整数)现在被破坏了,因为后置条件没有得到支持。

a) 为什么当被覆盖的方法削弱了先决条件时,它也被认为是违反 LSP的,因为该方法可能使用基本类型的合约不可接受的参数。因此,我们不能声称违反了基本类型的合同,因此也违反了 LSP 吗?

b) 为什么当被覆盖的方法增强后置条件时,它也不被认为是违反 LSP的,因为调用此方法的客户端只会收到原始方法可能结果的子集。因此,我们不能声称违反了基本类型的合同,因此也违反了 LSP 吗?

例子:

基类后置条件保证方法的返回值在范围内1-10,但随后子类型将后置条件更改为只允许返回值在范围内2-9。现在,处理从此方法返回的对象的代码(并假设后置条件在一个范围内1-10)被破坏了,因为后置条件没有得到支持。

0 投票
1 回答
164 浏览

java - 为什么 InflaterInputStream#available() 违反了里氏替换原则?

来自Android 参考

这种行为虽然与 RI 一致,但与 available() 不一致,违反了 Liskov 替换原则。不应使用此方法。

这种方法为什么以及如何违反原则?

作为一个附带问题,RI 代表什么?

0 投票
3 回答
713 浏览

java - 当“if else”/“instance of”不可避免时,除了使用访问者模式,我们如何改进设计?

当我们有一个纯粹是语义继承而不是行为继承的对象层次结构时,不可避免地我们需要在各处编写“instanceof”或“if/else”来进行运行时类型检查。

例如

如果我有一个对象层次结构

如果在这些类中有一个叫做calculate()的方法,那么我们就没有问题,我们可以利用多态性,这种设计满足LSP。

但是,如果我们出于某种原因不想将此 calculate() 方法添加到此层次结构中,这些对象是纯粹的普通对象,无状态对象仅代表语义。

然后我们被迫到处写下面的代码:

上面的代码表明了一个糟糕的设计,因为你到处都写了这个代码,这个设计很脆弱,以后很难改变。我想如果数字函数是有限的并且函数的计算在一个地方,这可能取决于复杂性。

到目前为止我所知道的是,要解决上述方法,唯一可能的方法是实现访问者模式,除了使用访问者模式之外,还有其他方法可以解决上述设计吗?

我从访问者模式中看到的一个问题是访问者模式的 accept 方法不返回值,如果 accept() 方法不能完全满足要求,这有时会很不方便。

0 投票
3 回答
3075 浏览

ruby - Square 和 Rectangle 继承有什么问题?

我读过一些关于让 Square 成为 Rectangle 类的继承类是一种不好的做法的文章,说它违反了 LSP(Liskov 替换原则)。我还是不明白,我在Ruby中做了一个示例代码:

谁能告诉我它有什么问题?

0 投票
1 回答
64 浏览

python - 如果 Field > CharField > EmailField,EmailField 是否打破了 CharField 的 Liskov 替换原则?

假设我正在编写一个带有Form类的 webapp,而一个Form类可以有多个Fields.

Field本身就是一个抽象类。它包含一个抽象validators属性,它是一个方法列表,它将调用以确定字段的内容是否有效。这些验证器通过调用实例方法来调用Field.run_validators(value)

CharField是一个Field允许任意文本的子类。这个字段总是有效的,只要给它一些非零长度的字符串。

EmailFieldCharField具有附加要求的子类。此字段仅在value通过一组某种测试时才有效。(例如'@' in value)。

我的问题是:是否会EmailField破坏 LSP CharField?它应该是一个兄弟类吗?尽管Field通过允许子类提供自己的 来定义可变性validatorsTextField但并未明确扩展该可变性。

我一直试图找到更多关于 LSP 的解释,但它们都重用了相同的 Rectangle/Square 示例。

鉴于:

使用时CharFieldtransmogulate(my_text_field)将毫无问题地运行。但是如果my_text_field是一个实例EmailField,它总是会引发一个ValidationError. 这是否违反了 LSP?还是我的推理完全倒退了?(这经常发生)

如果以某种方式改变分析,您也可以愉快地想象run_validators()返回False​​而不是引发异常;我只是想让我的示例尽可能接近源材料。

0 投票
1 回答
309 浏览

java - LSP 对像 Ruby 这样的动态类型语言也有意义吗?

考虑 Java 中的经典示例

我认为重点是子类的对象可以像 Java 这样的静态类型语言中的父类一样处理(类型转换?)

Rectange rectange = new Square();

但在 Ruby 中,我认为这没有任何意义,在 Ruby 中也是如此:

成为我总是可以使用以下方法检查对象的类:

rectange.class

在这种情况下,如果 Ruby 中的代码将返回Square

所以我不会像对待它一样对待它Rectange

谁能解释一下在像 Ruby 这样的动态类型语言中应用 LSP 的意义?


虽然我仍然不知道让 Square 成为 Rectangle 的孩子可能会导致什么问题。 但现在我学会了通过以下方式判断LSP是否紫罗兰色:

for squareobject 是SquareClass 的一个实例,rectangleobject 是Rectangleclass的一个实例

width=是他们两个中的一种方法

width=insquare不能用width=in代替rectangle

因为它不会像 'square' 中定义的那样设置高度。

我的这种思维方式错了吗?

并且我还学会了使用紫罗兰Rectangle类中的'width='方法来分析这个问题:

width=“矩形”类中

前提:@width并且@height有一定的价值。

postconditon:@width更改为新值,@height保持不变。

对于Square类中的“宽度=”

前提:同上

postconditon: '@width' 更改为新值,@height更改为新值

原则:要求不多,承诺不少

@height改变了,所以承诺没有实现,因此它不能是继承

有没有人可以通过使用给我一些关于我分析这个问题的方式的建议DBC

0 投票
2 回答
206 浏览

c# - Liskov 替换原理和冗余方法

我有一个名为 IRepository 的接口。该接口定义了一组通用方法,例如:

然后我有一个实现这个接口的类。这个类实际上使用实体框架来实现这些方法。然而,方法更新是多余的,因为实体框架会跟踪对检索到的实体所做的更改,所以我只需获取我想要的实体,更新它然后调用 SaveChanges。但是,将来我可能想用其他东西替换 IRepository 的这个具体实现。这可能不会像实体框架那样跟踪变化。所以我想我想把更新方法留在接口中,但是在我这个接口的具体实现中,只是把方法留在里面,但什么也不做。例如

这似乎符合 Liskov 替换原则,我可以用其他东西替换接口的实现。只是有些东西可能不需要实际实现接口上定义的所有方法。

这是一个好方法吗。我在想这没关系,甚至可能在 IRepository 的实现中将该方法标记为已过时,说明为什么它在此实现中已过时。

拥有一个什么都不做的更新方法并在整个应用程序中调用它似乎有点奇怪,即使它实际上并没有做任何事情。但是,如果我们将 IRepository 的实现更改为确实需要更新方法的实现,那么我们可以将其替换为不需要更改代码。

0 投票
0 回答
427 浏览

c# - 如何在 Windows 7 中增加传输提供程序的 UDP 缓冲区?

我一直在寻找如何增加 UDP 缓冲区,但没有解决方案。

我有某种通过 UDP JPEG 图像发送的网络摄像头。这些由 1024 字节的数据报包中的 cam(无 MTU 分段)划分。当图像大小接近 65K 时,图像会因为丢包而出错。我认为这是因为 UDP 传输提供程序的最大消息大小为 65527(0xfff7),您可以在 Windows SDK 中使用 SpOrder.exe 看到。

我尝试使用“Ws2_32.dll”中的函数 WSCUpdateProvider 更改此大小。我调用 WSCEnumProtocols 来获取 UDP 传输提供程序信息和 WSCGetProviderPath 因为它也是必需的,并且我得到了我需要的信息,但是当我使用管理权限调用 WSCUpdateProvider(无论给出什么信息)时,我总是得到错误:11003 (WSANO_RECOVERY )。

有什么我错过的技巧吗?我没有权利调用这个函数吗?我是否必须编写自己的 UDP 传输提供程序,或者是否有其他解决方案?

这是我在 C# 中的代码:

0 投票
2 回答
1411 浏览

java - 如何在 Java 中放入三维 Liskov 地图?

我正在尝试将地图放入另一个地图。

但我收到这个:

Map> 类型中的 put(String, capture#1-of ? extends Map) 方法不适用于参数 (String, Map)

Map<String,String>一样? extends Map<String,String>吗?

0 投票
2 回答
2349 浏览

oop - 这是否解决了 Liskov Substitution square-rectangle 违规?

我对 SOLID 设计原则非常陌生。我无法理解的一件事是 Liskov Substition Principle 违反的“方形矩形”示例。为什么 Square 的 Height/Width 设置器应该覆盖 Rectangle 的设置器?当存在多态性时,这不正是导致问题的原因吗?

删除它不能解决问题吗?

正如预期的那样,输出为 30。