Clean Code 짜기2
함수 당 추상화 수준은 하나로
한 함수 내에 추상화 수준을 섞으면 코드 해석에 많은 어려움이 생긴다.
추상화 수준이 높음 - getHtml()
추상화 수준이 적당함 - String pagePathName = PathParser.render(pagepath);
추상화 수준이 낮음 - append("\n")
코드는 위에서 아래로 한 함수 다음 추상화 수준은 한 단계 낮은 함수가 오도록 한다.
( TO 문단을 읽듯이 프로그램이 읽혀야 함) - 내려가기 규칙
추상화 함수의 핵심 - 짧으면서도 '한 가지'만 하는 함수
------------------------------------------
직원 유형에 따라 다른 값 계산해 반환하는 함수
public Money calculatePay(Employee e)
throws InvaIidEmployeeType {
switch (e.type) {
case COMMISSIONED:
return calculateCommissionedPay(e);
case HOURLY:
return calculateHourlyPay(e);
case SALARIED:
return calculateSalariedPay(e);
default:
throw new InvalidEmployeeType(e.type);
}
}
------------------------------------------
위 함수의 문제점
1. 새 직원 유형을 추가하면 함수의 길이가 더 길어진다.
2. 한 가지 작업만 수행하지 않는다.
3. 객체 지향 설계 방식 SRP를 위반한다.
( Single responsibility principle 단일 책임 원칙 : 한 클래스는 하나의 책이만 가져야 한다.)
4. 객체 지향 설계 방식 OCP를 위반한다.
(Open/closed principle 개방-폐쇄 원칙 : 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.)
5. 위 함수와 동일한 구조의 함수가 무한정 존재한다.
ex) isPayday(Employee e, Date date);
deliverPay(Employee e, Money pay);
해결 - switch 문을 추상 팩토리에 숨긴다.
switch 문을 사용해 Employee 파생 클래스의 인스턴스를 생성하고, 함수는 Employee 인터페이스를 거쳐 호출이 된다.
-> 다형성으로 인해 실제 파생 클래스의 함수가 실행된다.
------------------------------------------
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(EmployeeReco rd r) throws InvalidEmployeeType {
switch (r.type) {
case COMMISSIONED:
return new CommissionedEmployee(r) ;
case HOURLY:
return new HourlyEmployee(r);
case SALARIED:
return new SalariedEmployee(r);
default:
throw new InvalidEmployeeType(r.type);
}
}
}
------------------------------------------
참고한 책
클린 코드 (Clean Code)