Java - Switch문 리펙토링

<클린코드>

Posted by Yan on August 28, 2021

다형성을 활용해 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);
    }
}

문제점

  1. 함수가 길어서 새 직원 유형을 추가하면 더 길어진다
  2. 한 가지 작업만 수행하지 않는다
  3. SRPSingle Responsibility Principle를 위반한다. 코드를 변경할 이유가 여럿이기 때문이다.
  4. OCPOpen Closed Principle를 위반한다. 새 직원 유형을 추가할 때마다 코드를 변경하기 때문이다.
  5. 위 함수와 구조가 동일한 함수가 무제한 존재한다.

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);
        }
    }
}