关于罗伯特C马丁的_清洁代码_的例子问题

Jon*_*nah 5 java design-patterns

这是一个关于函数只做一件事的概念的问题.没有一些相关的上下文段落就没有意义,所以我在这里引用它们.它们出现在第37-38页:

换句话说,我们希望能够读取程序,好像它是一组TO段落,每个段落描述当前的抽象级别,并在下一级别引用后续的TO段落.

要包括设置和拆卸,我们包括设置,然后我们包括测试页面内容,然后我们包括拆卸.要包含设置,我们包括套件设置(如果这是套件),然后我们包括常规设置.

事实证明,程序员学习遵循这个规则并编写保持单一抽象级别的函数是非常困难的.但学习这个技巧也很重要.保持函数简洁并确保它们做"一件事"是关键.使代码读取像自上而下的TO段落是一种保持抽象级别一致的有效技术.

然后他给出了以下不良代码示例:

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);
}
}
Run Code Online (Sandbox Code Playgroud)

并解释了它的问题如下:

这个功能有几个问题.首先,它很大,当添加新的员工类型时,它会增长.其次,它显然不止一件事.第三,它违反了单一责任原则7(SRP),因为改变的原因不止一个.第四,它违反了开放封闭原则8(OCP),因为每当添加新类型时它必须改变.

现在我的问题.

首先,我很清楚它是如何违反OCP的,而且我很清楚,仅凭这一点就会使它设计不佳.但是,我试图理解每个原则,而且我不清楚SRP是如何应用的.具体来说,我可以想象这个方法改变的唯一原因是增加了新的员工类型.只有一个"变革之轴".如果需要更改计算的详细信息,这只会影响像"calculateHourlyPay()"这样的子方法

此外,虽然在某种意义上它显然做了3件事,这三件事都处于同一抽象层次,并且都可以被放入TO段中,与例子1没有区别:为了计算员工的工资,我们计算委托员工委托工资,小时工资,小时工资等.因此,除了违反OCP之外,这段代码似乎符合Martin对清洁代码的其他要求,即使他认为它没有.

有人可以解释我错过了什么吗?

谢谢.

Ara*_*ram 0

由于没有足够的背景,我在这里进行了长期的尝试。这个方法可能会因为两个原因而改变(顺便说一句,代码也违反了基本的封装原则)

  1. 当添加新员工类型但薪酬计算策略符合现有策略时
  2. 当添加新的员工类型并且需要新的薪资计算策略时

在这两种情况下,需要更改的抽象是添加的新 Employee 类型,而不是 Employee 类的客户端/用户。我的意思是说(工资计算应该被封装)calculatePay() 方法属于 Employee 抽象,如下所示

interface SalariedEmployee
{
BigDecimal calculatePay();
}

class HourlyEmployee implements SalariedEmployee
{
}

class CommissionedEmployee implements SalariedEmployee
{
}
Run Code Online (Sandbox Code Playgroud)