다형성을 활용해 Switch문 을 저차원 클래스에 숨기고 반복하지 않는 방법
나쁜 Switch문 예시
1
2
3
4
5
6
7
8
9
10
11
12
public Money calculatePay(Employee e) throws InvalidEmployType {
switch (e.type) {
case COMMISSIONED:
return calculateCommissionedPay(e);
case HOURLY:
return calculateHourlyPay(e);
case SALARIED:
return calculateSalariedPay(e);
default:
throw new InvalidEmployeeType(e.type);
}
}
문제점
- 함수가 길어서 새 직원 유형을 추가하면 더 길어진다
- 한 가지 작업만 수행하지 않는다
- SRP
Single Responsibility Principle
를 위반한다. 코드를 변경할 이유가 여럿이기 때문이다. - OCP
Open Closed Principle
를 위반한다. 새 직원 유형을 추가할 때마다 코드를 변경하기 때문이다. - 위 함수와 구조가 동일한 함수가 무제한 존재한다.
switch문을 리펙토링 하는 방법
- switch문을 추상 팩토리 메소드에 숨긴다. 꽁꽁 숨긴다.
- 팩토리는 switch문을 사용해 적절한 Employee 파생 클래스의 인스턴스를 생성한다.
- 구조가 같은 함수는 Employee 인터페이스를 거쳐 호출된다.
Abstract class
1
2
3
4
5
public abstract class Employee {
public abstract boolean isPayday();
public abstract Money calculatePay();
public abstract void deliverPay(Money pay);
}
Interface
1
2
3
public interface EmployeeFactory {
public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType;
}
Impl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 SalariedEmployee(r);
default:
throw new InvalidEmployeeType(r.type);
}
}
}