目前我正在阅读以下示例中的功能部分中的Uncle Bob的清洁代码书: -
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);
}
}
鲍勃叔叔说: -
此功能有几个问题。首先,它很大,而且 添加新员工类型时,它会增长。第二,非常 显然不止一件事。第三,它违反了Single 责任原则7(SRP)因为有多个原因 它改变了。第四,它违反了开放封闭原则8(OCP) 因为每当添加新类型时它必须改变
他提出了如下解决方案: -
public abstract class Employee {
public abstract boolean isPayday();
public abstract Money calculatePay();
public abstract void deliverPay(Money pay);
}
-- -- -- -- -- -- -- -- -
public interface EmployeeFactory {
public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType;
}
-- -- -- -- -- -- -- -- -
public class EmployeeFactoryImpl implements EmployeeFactory {
public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType {
switch (r.type) {
case COMMISSIONED:
return new CommissionedEmployee(r);
case HOURLY:
return new HourlyEmployee(r);
case SALARIED:
return new SalariedEmploye(r);
default:
throw new InvalidEmployeeType(r.type);
}
}
}
我无法从示例中完全理解这个想法,在我的脑海中有一些问题,我无法找到答案: -
添加新员工时,第一个代码中的 1-将会增长。是的,但这也发生在解决方案中,那么有什么区别呢?
2-第一个例子如何做多个事情。它只计算支付“在同一抽象层次上的功能”的注意事项,如果我们考虑抛出错误是另一回事,那么解决方案也是如此。
答案 0 :(得分:3)
First, it’s large, and when new employee types are added, it will grow.
你是对的,解决方案并没有真正缩短整体代码的大小,而且当添加新的员工类型时,它仍会整体增长。
Second, it very clearly does more than one thing.
原始文件都处理调度到正确的付款计算功能并计算付款。建议的解决方案解决了这个HourlyEmployee.calculatePay()
现在只计算HourlyEmployee
等的付费,EmployeeFactoryImpl
根据其返回的Employee
实施处理调度。
Third, it violates the Single Responsibility Principle (SRP) because there is more than one reason for it to change.
如果薪资计算逻辑需要更改,则原始calculatePay
需要更改。如果添加了新的员工类型,还需要更改。添加新员工类型时,解决方案不需要更改为calculatePay
。因此,只有一个责任和一个改变的理由。
Fourth, it violates the Open Closed Principle (OCP) because it must change whenever new types are added
返回1
,添加新员工类型时,整体代码长度仍会发生变化。但是,只有与处理员工类型相关的部分必须更改。专门用于计算薪酬的代码根本不需要改变。因此,需要扩展的部分是开放的,与扩展无关的部分是关闭的。
答案 1 :(得分:0)
1)更多代码更难理解,调试和维护。当然,这个例子并不是那么大,但你明白了。保持课程的小巧和重要性有助于可维护性,可扩展性和可重用性。更重要的是,如果您更改代码,为新员工类型添加新部分,则可能会破坏旧代码。
2)每次计算中的逻辑都会有所不同。因此,班级正在做三件事。如果将每个计算拆分为自己的类,则可以获得1中提到的好处,而且解决方案更加可测试。