问题标签 [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 投票
1 回答
218 浏览

java - Liskov 替换原则不同的数据类型

我的程序中的 LSP 有问题。我有一个抽象的基类和两种不同类型的产品,一种是食品,另一种是电子设备。我需要创建一个方法来返回这些产品的到期日期/保修。问题是一个是 Date 类型,另一个(保修)是 Int 类型......你知道如何制作一个同时满足这两种数据类型的方法吗?不使用 switch/if 语句,因为这将违反 OCP。

}

有没有什么办法可以修改这个功能来处理食品和电子产品,这样我就不必为每个新产品添加另一种方法?

这些是来自基类的方法

我尝试制作一种 getValidity 方法,但问题是对于食物它应该返回 Date,而对于电子产品应该返回 Int。有任何想法吗 ?

0 投票
3 回答
752 浏览

c# - 接口继承 - 如何不破坏 Liskov 的替换原则和单一职责模式?

我有一个通用存储库模式,我现在看到我需要一个自定义方法来实现这个模式的一个特定实现,让我们调用实现 CustomerRepository 和方法 GetNextAvailableCustomerNumber。我有一些想法,但它们不符合面向对象设计的 SOLID 原则。

我首先考虑为该实现创建一个自定义存储库模式(ICustomerRepository),但这并不是很可行。经验告诉我,肯定有其他一些我目前还没有考虑甚至不知道的方法。此外,我认为为道路上的每一个颠簸发明一个新的存储库接口不应该如此轻松。

然后我考虑让 ICustomerRepository 继承 IRepository<Customer> 并为 GetNextAvailableCustomer 添加方法签名,但这非常违反 Liskov 的替换原则,我相信它也略微违反了单一责任模式。即使我只想使用 ICustomerRepository,我仍然可以实现基于 IRepository 的客户存储库。我最终会得到两种选择,并且客户端应该实现哪个接口不再是显而易见的。在这种情况下,我希望它只能实现 ICustomerRepository,而不是 IRepository<Customer>

解决这个问题的正确方法是什么?接口继承真的是要走的路,还是有其他理想的符合 LSP 的首选方法?

这是我的通用存储库接口:

0 投票
2 回答
89 浏览

php - PHP 严格标准:这段代码有什么不合规之处?

如果我在 PHP 中使用 Stricts Standarts 编写此代码,则不符合要求:

这里失败的原理(如SOLId,...)是什么?

注意:如果我是对的,此代码尊重 Liskov 原则

0 投票
1 回答
732 浏览

c# - 继承和 Liskov 替换原则

在创建班级结构时,我正在努力遵守 Liskov 替换原则。我想在 Day 类中存储一组日历项目。需要有几种不同类型的 CalendarItems,例如:

AppointmentItem
NoteItem
RotaItem

它们都共享抽象基类 CalendarItem 中存在的一些通用功能:

但是例如RotaItem有一些额外的功能:

其他类也添加了自己的逻辑等。

我为我的日课收集了一组 CalendarBaseItem:

但是在回顾这一点时,我可以看到我违反了 LSP 原则,因为我必须检查并转换每个具体类型才能获得我希望每个子类的功能。

如果有人能建议如何避免这个问题,我将不胜感激。我应该使用组合方法并向每个最终类添加一个 CalendarItem 类,例如

这里唯一的问题是我需要为我的 Day 类中的每个 Concrete CalendarItem 单独收集一个集合吗?

0 投票
2 回答
218 浏览

inheritance - LSP 对加强先决条件的限制是否与需要向下转换表明设计不佳的建议相冲突

我最近开始阅读有关 Liskov 替换原则 ( LSP ) 的内容,并且我正在努力完全理解“不能在子类型中加强先决条件”这一限制的含义。在我看来,这种限制与建议应该最小化或完全避免从基类向下转换为派生类的需要的设计原则相冲突。

也就是说,我从一个Animal类开始,并派生出动物DogBirdHuman。LSP 对先决条件的限制显然符合自然,因为没有狗、鸟或人应该比一般动物类别更受限制。Bird.fly()坚持 LSP,派生类Human.makeTool()将添加特殊功能,例如Animal.

基类对每个可能的动物子类型的每个可能的特征都有虚拟方法感觉有点荒谬Animal,但如果没有,那么我需要向下转换Animal对其底层子类型的引用以访问这些独特的特征。然而,这种低调的需求通常被认为是糟糕设计的危险信号。Wikipedia 甚至暗示,由于 LSP,向下转换被认为是不好的做法

那么我错过了什么?

额外的问题:再次考虑上面描述的类层次结构Animals。显然,如果Animal.setWeight(weight)只需要一个非负数,这将违反 LSP,但Human.setWeight(weight)加强了这个前提条件并要求一个小于 1000 的非负数。但是对于 的构造函数呢Human,它可能看起来像Human(weight, height, gender)?如果构造函数对重量施加限制,是否会违反 LSP?如果是这样,应该如何重新设计这种层次结构以尊重衍生动物物理特性的明确界限?

0 投票
2 回答
779 浏览

oop - 向子类添加公共方法是否违反 LSP(Liskov 替换原则)?

如果我将公共方法添加到子类并且客户端程序调用添加的方法,则客户端程序不能使用父对象而不是子类。

这种情况违反了LSP?

0 投票
2 回答
344 浏览

oop - 如何考虑子类型的多态性

Liskov 替换原则指出:

超类型的不变量必须保留在子类型中。

我对这个原理和多态性的交集特别感兴趣。但实际上,特别是子类型多态性,参数多态性和 Haskell 类型类似乎就是这种情况。

所以,我知道函数是子类型,当它们的参数是逆变的并且它们的返回类型是协变的。我们可以假设方法只是带有隐式“self”参数的函数。但是,这似乎暗示如果子类覆盖父类的方法,则它不再是子类型,因为其中一个方法不再是子类型。

例如。采用以下伪代码:

所以回到 LSP:我们可以说即使这两个不遵循严格的子类型关系,属性 也Parent.increment()应该成立吗?Child.increment()

更一般地说,我的问题是:子类型化规则如何与多态函数的更具体的参数接口,以及将这两个概念结合在一起的正确思考方式是什么?

0 投票
1 回答
182 浏览

c++ - 沿模板类使用非虚拟接口向下转换

我正在实现一个有限元代码。

问题描述

在有限元方法中,我们需要一个积分器和一个插值器。积分器是对几何对象进行数值积分的对象,例如四边形、三角形等。积分器在几何对象内部放置多个积分点或横坐标,然后使用插值器逼近这些集成点的功能。

例如,一个四边形对象可以使用一个使用 4 个积分点的积分器。

其中@代表积分点的位置。插值器通过使用角节点处的值(由 * 表示)来近似函数在这些积分点处的值。您可以将其视为@ 的每个值是所有 * 值的一种平均值。

多态性概述

为方便起见,下表显示了此问题中使用的不同类之间的联系:

每个几何形状都有不同的坐标系,所以我的积分器和横坐标如下所示:

积分器.hpp

所有自然坐标横坐标的基类。

横坐标.hpp

四边形横坐标在 ξ 和 η 自然坐标上运行。

Abscissa_Quad.hpp

三角形横坐标在 ζ1、ζ2 和 ζ3 自然坐标上运行。

Abscissa_Tria.hpp

集成器实现将像这样集成:

积分器.cpp

到目前为止,一切都很好。让我向您展示我的插值器类。

插值器.hpp

从插值器中,我派生了所有几何形状的类。您可能会注意到我使用 Interpolator_Template 类作为基础。暂时忽略它,我将在一秒钟内解释细节。此类包含所有四边形共有的函数。

Interpolator_Quad.hpp

这个派生类对应于本题开头画的四边形。推导它的原因是因为可能存在具有更多插值节点的四边形。这个类实现了一个 QUAD_04 元素(一个有 4 个插值节点的四边形),但在有限元素中我们也有 QUAD_08、QUAD_09 等。

Interpolator_Quad_04.hpp

Interpolator_Quad_04.cpp

让我回到我之前错过解释的 Interpolator_Template 类。在我的代码中的某个时刻,我执行从 Abscissa * 到 Abscissa_Quad * 对象的向下转换。我通过将模板类与非虚拟接口模式结合使用来实现这一点。

插值器_模板.hpp

插值器_模板.cpp

我确信这段代码包含错误,因为我只需要复制和粘贴我认为理解我的观点所必需的内容,以及执行修改。但是,我希望我的想法能够正确地通过。

我知道向下转换通常是一种代码味道,所以在我开始为有限元中的所有几何形状实现积分器和插值器之前,我想听听你的意见。

我之前的尝试

这是我实现的最后一个设计模式。我将在下面解释我尝试过的其他设计;但是,您可以跳过阅读本节。

  • 一种双重调度设计模式(特别是访问者模式),其中积分器是派生的而不是插值器。例如,我有一个 Integrator_Quad_04 而不是 Interpolator_Quad_04。Integrator_Quad_04 有一个 Abscissa_Quad 作为成员变量,因为不再派生横坐标。

    然后,插值器成为积分器类的访问者,并访问其 _abscissae 成员变量。我决定不采用这种设计,因为那时插值器必须基于操作而不是形状来实现。

    /li>
  • 我尝试使用多次调度来做一些事情,但是所有形状所需的函数数量增长得非常快。

  • 双调度+模板的多种变体。

  • 我在这里找到了我正在使用的当前设计模式:

    面向对象的设计问题,Liskov 替换原则

结论

正如您可能从代码中推断的那样,我正在使用 C++11 进行编译。

您可能想知道为什么我不简单地将积分器和插值器组合成一个类,答案是因为积分器可能在四边形的子域上操作。例如,我可以在四边形内引入一个虚构的三角形并将积分点放在三角形内,但我仍然会使用四边形插值来近似三角形点内的解。当然,我需要在三角形和四边形坐标之间实现一些映射,但这是另一天的问题。

我想知道你是否认为向下转换不是解决这个问题的好方法,或者我是否遗漏了一些东西。也许我不了解解决此问题的设计模式,或者我的多态架构不正确。

任何反馈表示赞赏。谢谢!

0 投票
1 回答
301 浏览

java - Why use type substitution

Can anyone explain to me what is the need of using type substitution?

e.g.

What possible benifit can we get from the above code? Normally,

would have done the required job easily.

0 投票
1 回答
508 浏览

c# - 如何将独立 C# 应用程序中的 lsp 文件加载到 AutoCAD 中并等待它完成

第一次在这里海报。

我正在用 C# 构建一个独立的应用程序,我可以在其中删除一组 .dwg 并选择要在该组上运行的 .lsp 文件。我可以弄清楚如何打开 dwg、加载 .lsp 文件、保存 dwg 并关闭它。

我想不通的是如何等待所述 .lsp 文件完成,然后再转到下一个 .dwg。