switch문은 클린코드에 부적합하다. 이유는 크게 두 가지이다.
1. 여러가지 case가 있어 한 가지 함수에 다양한 작업이 포함될 수 있다.
2. 작게 만들 수 없다.
함수는 작고 한 가지 작업만 수행되어야 한다고 믿는 로버튼 C. 마틴에게 swith문은 부적합한 문법이다.
사용하기 어려운 switch문
// 월급 계산법
public Employee caculatePay(Employee e) {
switch(e.type) {
case COMMISSIONED : // 임원
case SALARIED : // 직원
case HOURLY : // 아르바이트
default : return null;
}
}
위 메소드는 월급 계산이라는 한 가지 작업만을 수행하는 것처럼 보이지만 실상은 다르다. case별 다른 계산방법이 존재하여 한 가지 메소드가 여러 상황을 통제해야 한다. 여러가지 상황은 다양한 유지보수 원인을 제공한다. 이는 메소드는 하나의 책임만 가져야 한다는 SRP(Single Responsibility Principle) 원칙에 어긋난다.
가장 큰 문제는 따로 있다.
월급 외에 휴가, 근무시간 등등 다양한 부분에서 직종별 분류가 필요하다. 직종별 분류가 필요할 때마다 swich문을 사용했다고 가정해보자. 만약 직종이 하나 더 추가되면 어떻게 될까? 월급 메소드, 휴가 메소드, 근무시간 메소드에 case를 모두 하나씩 더 추가해주어야 한다. 이는 OCP(Open Closed Principle) 원칙에 어긋난다.
이처럼 case가 많은 switch문은 유지보수에 많은 어려움을 만들 수 있다.
How to use switch문
그럼 switch문은 어떻게 사용해야 할까? switch문은 '단 한번만' 사용하면 충분하다.
그럼 언제?
다형적 객체를 생성할 때 사용하면 좋다.
대표적인 디자인 패턴에는 추상 팩토리 패턴이 있다.
객체A가 객체B를 직접 생성하면 서로 강하게 결합한다. 강한 결합은 유지보수에 좋지 않다. 객체생성작업을 담당하는 클래스를 따로 분리하는 것이 좋다. 이렇게 분리된 클래스를 '팩토리(Factory) 클래스'라 부른다.
팩토리(Factory) 클래스는 B인터페이스의 다양한 구현체를 생성하여 제공한다. A클래스가 B인터페이스의 구현체를 직접 생성하는 것이 아니라, Factory가 B인터페이스의 구현체를 생성한 후 A 클래스에게 '공급'한다. 이처럼 객체의 생성권한이 다른 클래스로 넘어간 것을 두고 제어의 역전(IOC)이라 부른다.
이런 IOC에서 switch문은 좋은 효과를 발휘한다. 상황에 따라 적절한 객체를 '공급'해줄 수 있기 때문이다.
< Employee 추상 클래스 >
public abstract class Employee {
public abstract boolean isPayDay();
public abstract Money calculate();
public abstract void deliverPay(Money pay);
}
Employee 추상 클래스는 CommissionedEmployee 클래스, SalariedEmployee 클래스, HourlyEmployee 클래스를 자식클래스로 갖는다. 그러므로 Employee 추상클래스는 3가지 형태로 구현가능하다. ( 다형성 )
카드리더기가 사원증을 긁으면 직원정보를 저장하는 프로그램을 만든다고 가정하자.
< EmployeeRecord 클래스 >
public enum EmployeeRecord {
COMMISSIONED, // 임원
SALARIED, // 직원
HOURLY; // 아르바이트
}
카드리더기는 COMMISIONED, SALARIED, HOURLY 까지 3가지 데이터를 갖는다. 사원증이 카드에 읽히면 3가지 중 하나의 데이터가 Factory 클래스로 입력된다.
< EmployeeFactory 클래스 >
public class EmployeeFactory {
public Employee makeEmployee(EmployeeRecord r) {
switch(r) {
case COMMISSIONED : return new CommissionedEmployee(r); // 임원 객체 생성
case HOURLY : return new HourlyEmployee(r); // 직원 객체 생성
case SALARIED : return new SalariedEmployee(r); // 아르바이트 객체 생성
default : return null;
}
}
}
Factory 객체는 makeEmployee(EmployeeRecord r) 의 매개변수로 COMMISIONED, SALARIED,HOURLY 중 한 가지 데이터를 받는다. 그 후, switch문에 의해 3가지 객체 중 하나가 선택되어 생성된다.
이처럼 switch문을 다형성 있는 객체 생성에 사용하면 switch문의 특성이 단점이 아닌 장점으로 바뀔 수 있다.
'개발교양도서 > 클린코드' 카테고리의 다른 글
[클린코드] 명령과 조회를 분리하라 (0) | 2022.10.11 |
---|---|
[클린코드] 매개변수의 개수 (0) | 2021.10.20 |
[클린코드] 출력인수를 가급적 피하라 ( this의 존재 이유 ) (0) | 2021.10.20 |
[클린코드] 한 가지 추상화, 한 가지 추상화 수준 [ 함수 ] (0) | 2021.07.30 |
[클린코드] 깨끗한 코드란 무엇인가? (0) | 2021.07.10 |