当前位置: 首页 > 面试题库 >

是否有不止一种方法违反单一责任原则?

叶鸿振
2023-03-14
问题内容

我对单一责任原则感到困惑。 《原则》指出,阶级改变只有一个原因。

我面临的问题是,对方法的任何更改或在执行操作中的任何逻辑更改都会更改类。例如,考虑以下类:

class Person{
    public void eat(){ };
    public void walk(){ };
    public void breathe(){ };
    public void run(){ };
    public void driveCar(Car car){ };
}

鲍勃叔叔将其描述为 仅由一个人/演员负责更改 。我有以下两个问题:

  1. 对于上述阶层,谁是负责变革的演员/人?
  2. 饮食,呼吸或行走的逻辑上的任何改变都不会改变人的类吗?难道这并不意味着每种方法都是改变的理由,因为做事的逻辑可能会改变吗?

问题答案:

改变的原因是什么

  1. 对于上述阶层,谁是负责变革的演员/人?

一个演员是:用户(包括客户,利益相关者,开发者组织)或外部系统。
我们可以争辩说人是否是系统,但这不是这里或那里。

另请参阅: 用例。

  1. 饮食,呼吸或行走的逻辑上的任何改变都不会改变人的类吗?难道这并不意味着每种方法都是改变的理由,因为做事的逻辑可能会改变吗?

不,方法不是改变的理由。方法可以改变……但是为什么会改变呢?是什么会触发开发人员进行更改?

单一责任原则的一部分是,代码最多应与一个外部系统进行交互。 请记住,并非所有参与者都是外部系统,但有些是。
我认为大多数人会觉得SRP的这一部分易于理解,因为我们可以在代码中看到与外部系统的交互。

但是,这还不够。例如,如果您的代码必须计算税金,则可以在代码中对税率进行硬编码。这样,它就不会与任何外部系统进行交互(它只是使用一个常量)。但是,在一项税收改革之后,政府已被披露为更改您的代码的原因。

您应该能够做的就是互换外部系统(也许需要额外的编码工作)。例如,从一个数据库引擎更改为另一个。但是,我们不希望这些更改之一转换为代码的完全重写。更改不应传播,更改也不应破坏其他内容。为了确保这一点,我们希望隔离所有与数据库引擎相关的代码(在此示例中)。

因相同原因而变化的事物应归为一组,因不同原因而变化的事物应分开。-罗伯特·马丁

我们可以用上面的政府示例做类似的事情。我们可能不希望软件读取会议记录,而可以让它读取配置文件。现在,外部系统是文件系统,并且将有代码与之交互,并且该代码不应与其他任何交互。

我们如何确定这些变化的原因?

您的代码由一组要求定义。有些功能正常,有些则没有。如果这些要求中的任何一项发生更改,则您的代码必须更改。更改需求的原因是更改代码的原因。

注意 :可能没有记录所有需求,但是仍然有未记录的需求。

然后,您需要知道这些要求从何而来。谁或什么可以改变他们?这些就是您改变的原因。可能是公司政策的变化,可能是我们添加的功能,可能是新法律,可能是我们正在迁移到其他数据库引擎或操作系统,并翻译成另一种语言,适应另一个国家等

其中一些是代码与之交互的外部系统(例如数据库引擎),而有些则不是(公司的政策)。

责任怎么办

您想隔离它们。因此,您将拥有与数据库交互的代码,仅此而已。您将拥有实现业务规则的代码,仅此而已。等等。

意识到即使代码的每个部分的实现将依赖于外部的东西,它们的接口也不必一定要这样做。因此,定义接口并注入依赖项,以便您可以更改每个部分的实现而不必更改其他部分……也就是说,代码部分的实现不应成为更改代码其他部分的实现的理由。

注意
:您的代码的任何部分都不应承担多重责任。让代码的一部分负责每个职责,让代码的一部分负责将其他部分放在一起。同样,如果您的代码的一部分不承担任何责任,则没有理由保留它。因此,您的代码的每一部分都应完全负责。

对于您的代码,请问自己,Person该类的要求是什么。他们完成了吗?它们来自哪里?他们为什么要改变?

推荐观看

有关单一责任原则的更权威解释,请参阅2015年挪威开发者大会上的Robert C Martin-
单一责任原则(51分钟8秒,英语)。



 类似资料:
  • 问题内容: Liskov替换原理是SOLID的原理之一。我已经读过几次这个原理,并试图理解它。 这就是我的所作所为, 此原则与类层次结构之间的强行为契约有关。子类型应该能够被超类型替换而不会违反合同。 我也读过其他文章,对这个问题我有些失落。难道方法不违反LSP? 上面链接的文章摘录: 换句话说,当通过对象的基类接口使用对象时,用户仅知道基类的前提条件和后置条件。因此, 派生对象不能期望此类用户遵

  • 根据方法<code>java.util.concurrent的约定。未来#取消: 此方法返回后,对 isDone 的后续调用将始终返回 true。 Netty的Future接口扩展了它: 所以Netty应该遵守合同。但事实上Netty没有。您可以运行以下示例代码: 控制台应打印: 真 但实际上它打印: 假 以下方法也违反了合同: 我已经在github上创建了一个问题:问题 但是我仍然想在stack

  • 在Spock规范中,expect:或then:block中的任何行都被计算并断言为,除非它具有返回类型为的签名。 方法在类中定义如下: 我故意在那里断言,这样它就不会失败。即使失败并出现错误: 如何以及为什么方法调用结果被计算为?

  • 如果S是T的一个子类型,那么T类型的对象可以被S类型的对象替换。 子类有两种不同的行为(选中与未选中),在某些情况下,除非更改当前代码,否则无法用子类对象有效地替换基类用法,例如,如果编写如下代码: 这是违反吗?,为什么/为什么不?。 资料来源:http://www.oracle.com/technetwork/articles/entarch/effective-exceptions-09234

  • 高凝聚力是单一责任原则的同义词吗?如果没有,它们有什么不同?

  • 我是OOP的新手。最近我读到了关于Liskov替换原理的文章。 在下面给出的代码中,Square类继承Give_区域。假设Square类与Square相关(比如有效性检查)。Give_Area给出正方形的面积(4个顶点位于圆的周长上)和圆的面积。所以,如果给我一个半径,我必须打印圆和正方形的面积(由放置在圆周长上的顶点组成)。为了得到圆的面积,我使用了一个参数。但在求平方面积时没有参数。因此,我在