리팩토링 30. 기본형을 객체로 바꾸기
- etc/리팩토링
- 2023. 5. 10.
들어가기 전
이 글은 인프런 백기선님의 강의를 복습하며 작성한 글입니다.
리팩토링 30. 기본형을 객체로 바꾸기 (Replace Primitive with Object)
- 상황
- 개발 초기에는 기본형 (숫자/문자열)으로 표현한 데이터만으로 기능을 충분히 구현 가능함.
- 요구 사항이 추가되면서, 기본형만으로는 표현할 수 없어짐.
- 예) 전화번호에 지역 코드가 필요해진 경우.
- 예) 온도에 단위 변환이 필요한 경우.
- 리팩토링 방법
- 기본형을 사용한 데이터를 감싸줄 클래스를 만들면, 필요한 기능을 추가할 수 있다.
개발 초기에는 데이터를 표현할 때 기본형을 사용하는 것이 나쁘지 않다. 그런데 어플리케이션이 발전하면서 기본형만으로는 원하는 요구사항을 구현/표현하지 못할 수도 있다. 예를 들어 Int를 이용해 섭씨 온도만 표현하고 있던 상황에서 화씨 온도까지 표현해야 한다면, int만으로는 부족하지 않다.
이처럼 기본형 데이터 타입을 필요에 의해서 객체 타입으로 변경하는 것을 '기본형 객체로 바꾸기' 리팩토링이다.
코드
아래 코드에서 OrderProcessor는 Order 클래스의 우선순위를 판단하고 있다. 이 때 Order 클래스의 우선순위는 문자열이 특정한 값을 가지는지로 판단을 하고 있는데, 문자열만으로 우선순위를 구현하는데는 한계가 있다. 특히 문자열로 Order의 우선순위를 판단하려면 If / Else 문을 많이 사용해야해서 코드가 아주 더러워 질 수 있다.
이런 문제는 우선순위를 문자열이 아닌 다른 객체로 표현하도록 하는 것이다. 즉, 기본형을 객체로 바꿔야한다.
public class OrderProcessor {
// Order의 우선순위를 파악하는데, 문자열로 처리하고 있음.
// 문자열로 우선순위의 랭킹을 설정하기 어려움. --> 기본형에서 객체로 변경이 필요함.
public long numberOfHighPriorityOrders(List<Order> orders) {
return orders.stream()
.filter(o -> o.getPriority() == "high" || o.getPriority() == "rush")
.count();
}
}
기본형을 객체로 바꾸기 리팩토링은 다음 순서로 진행한다.
- Priority 클래스를 생성한다. 필드값으로 value를 가지고, 이 값은 Priority 클래스의 우선순위를 나타낸다.
- Priority 클래스는 필드로 low, normal, high, rush를 리스트로 가진다.
- Priority 생성자에서 value가 유효한 값인지 Validation을 추가한다.
- OrderProcessor에서 값 비교를 하기 위한 HighThan() 메서드를 구현한다. 특정 문자열의 List 내부에서의 Index로 우선순위를 판단한다.
- Order 클래스의 String Priority를 String PriorityValue로 바꿔준다. 필드에 Priority priority를 추가한 후에 메서드를 수정한다.
- OrderProcessor도 수정된 코드를 사용하도록 반영해준다.
수정이 완료된 코드는 다음과 같아진다.
public class Priority {
private String value;
private List<String> legalValues = List.of("low", "normal", "high", "rush");
public Priority(String value) {
if (legalValues.contains(value))
this.value = value;
else
throw new IllegalArgumentException("illegal value for priority" + value);
}
public boolean higherThan(Priority other) {return this.index() > other.index();}
private int index() {return this.legalValues.indexOf(this.value);}
}
public class Order {
private Priority priority;
public Order(Priority priority) {this.priority = priority;}
public Priority getPriority() {return priority;}
}
public class OrderProcessor {
// Order의 우선순위를 파악하는데, 문자열로 처리하고 있음.
// 문자열로 우선순위의 랭킹을 설정하기 어려움. --> 기본형에서 객체로 변경이 필요함.
public long numberOfHighPriorityOrders(List<Order> orders) {
return orders.stream()
.filter(o -> o.getPriority().higherThan(new Priority("normal")))
.count();
}
}
이 리팩토링의 가치
- 기존에는 Priority 변수를 String 타입으로 사용했다. String 타입만으로는 Priority의 우선순위 비교가 어려웠다.
- Priority를 String 클래스에서 새롭게 Priority 클래스를 사용하도록 변경했다. 이를 이용해 Priority의 우선순위 비교등을 더욱 쉽게 가져갈 수 있게 되었다.
'etc > 리팩토링' 카테고리의 다른 글
리팩토링 32. 조건부 로직을 다형성으로 바꾸기 (0) | 2023.05.10 |
---|---|
리팩토링 31. 타입 코드를 서브클래스로 바꾸기 (0) | 2023.05.10 |
냄새 11. 기본형 집착 (0) | 2023.05.10 |
냄새 10. 데이터 뭉치 (Data Clumps) (0) | 2023.05.10 |
냄새 9. 기능 편애 (0) | 2023.05.10 |