- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
这是一个关于函数只做一件事的概念的问题。如果没有一些相关的上下文上下文就没有意义,所以我会在这里引用它们。它们出现在第 37-38 页:
To say this differently, we want to be able to read the program as though it were a set of TO paragraphs, each of which is describing the current level of abstraction and referencing subsequent TO paragraphs at the next level down.
To include the setups and teardowns, we include setups, then we include the test page content, and then we include the teardowns. To include the setups, we include the suite setup if this is a suite, then we include the regular setup.
It turns out to be very difficult for programmers to learn to follow this rule and write functions that stay at a single level of abstraction. But learning this trick is also very important. It is the key to keeping functions short and making sure they do “one thing.” Making the code read like a top-down set of TO paragraphs is an effective technique for keeping the abstraction level consistent.
然后他给出了以下糟糕代码的示例:
public Money calculatePay(Employee e)
throws InvalidEmployeeType {
switch (e.type) {
case COMMISSIONED:
return calculateCommissionedPay(e);
case HOURLY:
return calculateHourlyPay(e);
case SALARIED:
return calculateSalariedPay(e);
default:
throw new InvalidEmployeeType(e.type);
}
}
并解释了它的问题如下:
There are several problems with this function. First, it’s large, and when new employee types are added, it will grow. Second, it very clearly does more than one thing. Third, it violates the Single Responsibility Principle7 (SRP) because there is more than one reason for it to change. Fourth, it violates the Open Closed Principle8 (OCP) because it must change whenever new types are added.
现在我的问题。
首先,我很清楚它是如何违反 OCP 的,而且我很清楚,仅此一点就使它的设计很糟糕。但是,我试图理解每条原则,但我不清楚 SRP 是如何应用的。具体来说,我能想到的改变这种方法的唯一原因是增加了新的员工类型。只有一个“变化轴”。如果计算的细节需要改变,这只会影响像“calculateHourlyPay()”这样的子方法
此外,虽然在某种意义上它显然在做 3 件事,但这三件事都处于同一抽象级别,并且都可以放入一个 TO 段落中,与示例一无异:TO calculate pay对于员工,如果员工是受委托(delegate)的,我们计算委托(delegate)工资,如果他是小时工,我们计算小时工资,等等。。因此,除了违反 OCP 之外,这段代码似乎符合 Martin 对干净代码的其他要求,尽管他辩称不符合。
有人可以解释一下我错过了什么吗?
谢谢。
最佳答案
calculatePay 发生变化似乎有两个原因:
两个不同的变化轴。但是,calculatePay 方法的职责是支付计算。只有在薪酬计算公式发生变化时,它才应该发生变化。我认为这就是作者声明该方法违反 SRP 的原因。
在书中,作者提供了一个解决方案,他为派生自公共(public) Employee 抽象基类的每个员工类型定义类。他将 calculatePay 方法移至 Employee 基类,并定义了一个 Employee 工厂类,该类在给定员工类型的情况下创建适当的员工对象。这样每个工资计算都封装在一个特定的员工类型类中,因此不受员工类型变化的影响。此外,这个简单解决方案中的员工工厂类仅受员工类型变化的影响。因此,新的解决方案让 SRP 很高兴。
在新的解决方案中,你要求员工计算他/她的工资,我不喜欢,因为这不反射(reflect)现实。您实际上可以争辩说这也违反了 SRP。这个计算是工资部门的责任。我喜欢软件中的模型尽可能代表现实世界的领域,但我们通常不得不做出妥协。在这种情况下,我会说员工类型的变化不会定期发生。事实上,它们很可能很少发生。因此,我会将事情保留在对业务领域有意义的地方,例如要求工资单对象计算员工工资。与此同时,我将拥有并保留一套广泛的单元测试,因为人们应该拥有这些单元测试,以确保当员工类型发生变化时,一切都继续按预期工作。
关于java - 关于 Robert C Martin Clean Code 中示例的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4533111/
我试图理解这个草图,但无法理解。如果我错了,请纠正我,但基本上,假设我有一个文本数据..单词..我有一个散列函数..它接受一个单词并创建一个整数散列,然后我将该散列转换为二进制位向量?正确的..然后我
我正在考虑实现 Robert Martin 的 Clean Architecture在一个项目中,我试图找出如何处理非平凡用例。 我发现很难将架构扩展到复杂/组合的用例,尤其是参与者是系统而不是用户的
我正在尝试实现 Clean Architecture由罗伯特·马丁描述。更具体地说,我正在使用 VIPER这是 Clean Architecture 的 iOS 版本。 我遇到的问题如下: 用户开始查
好吧,Martin Fowler 从 POEAA 一书中介绍了这种工作单元的概念。如果您想拥有自动提交系统,它会非常有效,在该系统中,您的域模型使用工作单元将自己标记为新的、脏的、已删除的或干净的。然
我正在研究 Coq 并试图证明 Martin-Lof 的等式和路径归纳的等式之间的同构。 我将这两个等式定义如下。 Module MartinLof. Axiom eq : forall A, A -
在 Martin Odersky 的演讲中:http://youtu.be/9PkxE_L_LMo ,在第 49 分钟,他谈到了一个问题,即由于静态数据,“编译器不可重入”。 我对“可重入”一词在 J
我阅读了 Robert Martin 关于接口(interface)隔离原则的文章 here .在文章的最后,在解决 ATM UI 架构的问题时,他说: Consider also that each
这个问题不太可能帮助任何 future 的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况有关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,visit
以下是我为实现 Flajolet and Martin’s Algorithm 而编写的代码.我使用 Jenkins 哈希函数 生成数据的 32 位哈希值。该程序似乎遵循了该算法,但偏离了大约 20%
这是一个关于函数只做一件事的概念的问题。如果没有一些相关的上下文上下文就没有意义,所以我会在这里引用它们。它们出现在第 37-38 页: To say this differently, we wan
在Domain Logic and SQL , Martin Fowler 谈到了 3 种与数据库接口(interface)的方式: 交易脚本 领域模型,以及 SQL 中的逻辑 我想知道的是: 在使用
我正在处理Odersky's ScalaDays 2011 keynote talk ,当我到达这一特定行时(分配 charCode),他用极少的代码行构建了一个电话号码同义词生成器: val mne
const mostLikes = (blogs) => { if (!blogs.length) { return 0 } const distinctAuthors = [..
我正在使用 Martin Peris 代码使用 OpenCV 和 PCL 进行 3D 重建(链接如下): http://blog.martinperis.com/2012/01/3d-reconstr
我正在实现前向后向/Baum-Welch 算法,如 Jurafsky + Martin 的语音和语言处理(第 2 版)中所述,作为词性标注器。我的代码大致结构如下: #Initialize trans
我想调整简单容器的高度,以匹配使用 $.ajax 从服务器返回的数据传递的不断变化的深度要求。 似乎一旦触发模态,所有 CSS 都会即时更改,例如$('#someid').css('高度','500p
目前正在学习在线类(class)《响应式编程原理》由 Martin Odersky、Erik Meijer、Roland Kuhn 编写,一年前就已经结束了,我想这门类(class)的讨论论坛中没有人
马丁·福勒 (Martin Fowler) 说 avoid automatic deserialization在 API 中: I prefer to avoid automatic deserial
我决定尝试学习 Electron ,所以我克隆了 electron quick start并使用 npm i 安装依赖项然后跑 npm start但由于此错误,我需要帮助: dyld: Symbol
我是一名优秀的程序员,十分优秀!