关于示例的问题在Robert C Martin的_Clean Code_

这是一个关于函数只做一件事的概念的问题。没有一些相关的上下文段落就没有意义,所以我在这里引用它们。它们出现在第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);
}
}
并解释了它的问题如下:   这个功能有几个问题。首先,它很大,而且很新   员工类型被添加,它会增长。其次,它显然不止一件事。   第三,它违反了单一责任原则7   (SRP)因为不止一个   它改变的原因。第四,它违反了开放封闭原则8   (OCP)因为它   每当添加新类型时必须更改。 现在我的问题。 首先,我很清楚它是如何违反OCP的,而且我很清楚,仅凭这一点就会使它设计不佳。但是,我试图理解每个原则,而且我不清楚SRP是如何应用的。具体来说,我可以想象这个方法改变的唯一原因是增加了新的员工类型。只有一个“变革之轴”。如果需要更改计算的详细信息,这只会影响像“calculateHourlyPay()”这样的子方法 此外,虽然在某种意义上它显然做了3件事,这三件事都处于同一抽象层次,并且都可以被放入TO段中,与例子1没有区别:为了计算员工的工资,我们计算如果雇员受委托则委托工资,如果他是小时工资则按小时计算等等。因此,除了违反OCP之外,这段代码似乎符合马丁对清洁代码的其他要求,即使他认为它没有。 有人可以解释我错过了什么吗? 谢谢。     
已邀请:
calculatePay似乎有两个原因需要改变: 员工类型的变化 薪酬计算的变化 两个不同的变化轴。但是,calculatePay方法的责任是工资计算。只有在薪酬计算公式发生变化时才应该更改。我认为这就是作者声明该方法违反SRP的原因。 在本书中,作者提供了一个解决方案,他为每个员工类型定义了从公共Employee抽象基类派生的类。他将calculatePay方法移动到Employee基类,并定义了一个Employee工厂类,该类在给定员工类型的情况下创建适当的员工对象。这样,每个薪资计算都封装在特定的员工类型类中,因此不受员工类型更改的影响。此简单解决方案中的员工工厂类也仅受员工类型更改的影响。因此,新的解决方案让SRP感到高兴。 在新的解决方案中,您要求员工计算他/她不喜欢的工资,因为这并不反映现实。你实际上可以说这也违反了SRP。此计算由薪资部门负责。我喜欢它,软件中的模型尽可能地代表真实世界域,但我们通常必须做出妥协。在这种情况下,我会说员工类型的变化不会定期发生。事实上,他们很可能很少发生。因此,我会将事情保存在他们理智的业务领域,例如要求工资对象计算员工薪酬。与此同时,我将拥有并保持广泛的单元测试,因为必须确保当员工类型发生变化时,一切都会按预期继续工作。     
因为我没有足够的背景,所以我在这里进行了长时间的拍摄。由于两个原因,这种方法可能会改变(顺便说一下,代码也违反了基本的封装原则) 添加新员工类型但薪酬计算策略符合现有策略时 添加新员工类型时,需要新的薪资计算策略 在这两种情况下,需要更改的抽象是添加的新Employee类型,而不是Employee类的客户端/用户。我的意思是说(付费计算应该封装)calculatePay()方法属于员工抽象,下面是石灰
interface SalariedEmployee
{
BigDecimal calculatePay();
}

class HourlyEmployee implements SalariedEmployee
{
}

class CommissionedEmployee implements SalariedEmployee
{
}
    
我也想弄清楚,如果你不是,我想我可能会找到一些东西来说服你。 实际上有两个原因可以改变这种方法: 薪酬计算:因为您可以出于任何原因决定现在使用月度策略支付HourlyPaidEmployee。您没有更改计算的正确公式,而是您支付此类员工的方式,这基本上是对同一抽象级别的更改。 员工类型的变化:您可以添加其他类型的员工(自由职业者),甚至可以将该类型重命名为其他类型。 邮政似乎有点旧,但我希望这有助于其他人理解。     

要回复问题请先登录注册