Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 关于罗伯特·C·马丁的例子的问题';s_清洁代码__Java_Design Patterns - Fatal编程技术网

Java 关于罗伯特·C·马丁的例子的问题';s_清洁代码_

Java 关于罗伯特·C·马丁的例子的问题';s_清洁代码_,java,design-patterns,Java,Design Patterns,这是一个关于函数只做一件事的概念的问题。如果没有一些上下文相关的段落,这是没有意义的,所以我将在这里引用它们。它们出现在pgs 37-38上: 换言之,我们希望能够像读取一个集合一样读取程序 of TO段落,每个段落都描述了当前的抽象级别,并引用了下一级别的后续段落 为了包括设置和拆卸,我们先包括设置,然后包括测试页面内容,然后包括拆卸。为了包括设置,我们包括套件设置如果这是套件,那么我们包括常规设置 事实证明,程序员很难学会遵守这一规则并编写代码 停留在单一抽象级别的函数。但是学习这个技巧也是

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

换言之,我们希望能够像读取一个集合一样读取程序 of 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件事,但这三件事都处于相同的抽象层次,并且都可以放在一个与示例一相同的段落中:为了计算员工的薪酬,如果员工是受委托的,我们计算委托的薪酬,如果他是每小时的,我们计算每小时的薪酬,因此,除了违反OCP之外,该准则似乎符合Martin的清洁准则的其他要求,尽管他认为不符合

有人能解释一下我遗漏了什么吗


谢谢

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

  • 添加新员工类型但薪酬计算策略符合现有策略时
  • 添加新员工类型时,需要新的薪酬计算策略
  • 在这两种情况下,需要更改的抽象是添加的新员工类型,而不是Employee类的客户机/用户。我的意思是,(工资计算应该封装)calculatePay()方法属于下面的Employee抽象

    interface SalariedEmployee
    {
    BigDecimal calculatePay();
    }
    
    class HourlyEmployee implements SalariedEmployee
    {
    }
    
    class CommissionedEmployee implements SalariedEmployee
    {
    }
    

    Calculate可能会发生更改,原因似乎有两个:

  • 员工类型的变化
  • 薪酬计算的变化
  • 两个不同的变化轴。然而,calculatePay方法的责任是薪酬计算。只有在薪资计算公式发生变化时,才应更改。我认为这就是为什么作者声明该方法违反了SRP

    在本书中,作者提供了一个解决方案,其中他为每个雇员类型定义了类,这些雇员类型派生自一个公共雇员抽象基类。他将calculatePay方法移动到Employee基类,并定义一个Employee工厂类,该类在给定Employee类型的情况下创建适当的Employee对象。这样,每个薪酬计算都封装在特定的员工类型类中,因此不受员工类型更改的影响。此外,此简单解决方案中的employee factory类仅受员工类型更改的影响。因此,新的解决方案使SRP感到高兴


    在新的解决方案中,您要求员工计算他/她的工资,我不喜欢,因为这不能反映实际情况。实际上,你可以说这也违反了SRP。该计算由工资部门负责。我喜欢软件中的模型尽可能地代表现实世界的领域,但我们通常不得不做出妥协。在这种情况下,我认为员工类型的变化不会定期发生。事实上,它们很可能很少发生。所以,我会把事情放在业务领域有意义的地方,比如让payroll对象计算员工工资。同时,我将拥有并保留一套广泛的单元测试,因为我们应该确保当员工类型发生变化时,一切都能按预期进行。

    我也在努力解决这个问题,我想如果你不这样做,我可能会找到一些东西来说服你

    改变这种方法实际上有两个原因:

  • 薪酬计算:因为你可以根据任何理由决定一名HourlyPaide员工现在将使用每月策略获得薪酬。你不是在改变正确的计算公式,而是在同一抽象层次上改变了你支付这类员工的方式
  • 员工类型的更改:您可以添加其他类型的员工(自由职业者),甚至可以将该类型重命名为其他类型
    这篇文章似乎有点陈旧,但我希望这能帮助其他人理解

    嗯。。。。在这两种情况下,它仍然需要将新员工类型添加到