Oop 在干净代码示例中理解单一责任主体SRP
目前,我正在阅读Bob叔叔的干净代码手册,在函数部分中查看以下示例:-Oop 在干净代码示例中理解单一责任主体SRP,oop,design-patterns,coding-style,single-responsibility-principle,Oop,Design Patterns,Coding Style,Single Responsibility Principle,目前,我正在阅读Bob叔叔的干净代码手册,在函数部分中查看以下示例:- public Money calculatePay(Employee e) throws InvalidEmployeeType { switch (e.type) { case COMMISSIONED: return calculateCommissionedPay(e); case HOURLY: return calculateH
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),因为有不止一个原因 让它改变。第四,它违反了开闭原则(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-第一个示例如何做不止一件事。它只计算支付“在同一抽象层次的函数”注意到如果我们考虑抛出错误是另一回事,解决方案也太过了。
BR/> < P > 1)更多代码更难理解、调试和维护。当然,这个例子没有那么大,但你明白了。保持类的小型化和针对性有助于维护性、可扩展性和可重用性。此外,如果您更改代码,为新员工类型添加新的部分,则可能会破坏旧代码 2) 每次计算的逻辑都会有所不同。因此,全班正在做三件不同的事情。如果您将每个计算划分为自己的类,您将获得1中提到的好处,而且解决方案更易于测试
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
等员工的工资。employeefactoryemploy
根据其返回的员工
实现处理派遣
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
,添加新员工类型时,代码的总长度仍将更改。但是,只有与处理员工类型相关的部分需要更改。用于计算工资的代码根本不需要更改。因此,需要扩展的部分是开放的,而与扩展无关的部分是关闭的。如果我们考虑计算佣金小时工资超过一件事,我注意到它们都是“第一代码”中的函数(在同一抽象级别),所以他们做了一件事,Uncle Bob说。“如果函数只执行比函数名称低一级的步骤,则函数只执行一件事“清除代码第36页当然,在应用解决方案后,calculatePay函数将不需要更改,而更改将应用于工厂类EmployeeFactoryImpl,这是否可以接受?@MostafaDarwish原始版本不需要只执行函数名称下方的第1级步骤。除了计算付款外,calculatePay
还处理发送到正确付款计算功能的操作。如示例所示,这不是“比函数的指定名称低一级”。我们可以清楚地看到这一点,因为EmployeeFactoryImpl
,它不知道任何计算工资的逻辑,仍然可以正确地处理调度。好的,我们把它称为“to”:-“要计算薪酬,我们应该选择员工类型,要选择员工类型,我们会切换员工类型,如果是佣金,我们会计算佣金…”你说得对,他们不在同一级别