✍️ 악취 14 : 성의없는 요소
개발과정에서 정의된 변수, 메서드, 클래스가 시간이 지남에 따라 필요 없는 경우가 있다. 가령 확장성을 고려해서 미리 추가된 변수와 기능들이 그러한 경우에 속한다. 혹은 리팩토링의 결과로 더 이상 필요 없는 요소들이 나올 수 있다. 리팩토링 책의 저자는 이와 같은 요소를 '성의 없는 요소'라고 정의했다.
재사용을 고려해서 함수 추출하기 리팩토링이 적용된 어느 메서드가 계속해서 재사용이 되지 않고 한 곳에서만 사용한다면 '함수 인라인'을 적용할 수 있다. 이와 유사하게 클래스의 경우라면 '클래스 인라인'을 적용하면 된다.
여기 성의 없는 요소 악취를 해결하기 위한 세 가지 리팩토링 기법이 있다.
1. "함수 인라인"
2. "클래스 인라인"
3. "계층 합치기" 불필요한 상속 구조 제거
본 포스팅에서 관심 있게 살펴볼 리팩토링은 불필요한 상속 구조를 해결하기 위한 '계층 합치기'이다.
🍊 계층 합치기
상속 구조를 리팩토링 하는 과정에서 일부 하위 클래스를 삭제하거나, 기능을 올리고 내리다 보면 상위 클래스와 하위 클래스의 차이가 없는 경우가 발생한다. 이러한 경우 계층 합치기 리팩토링을 적용할 수 있다.
여기 등급에 따른 서로 다른 할인율과 혜택을 받는 클래스가 상속의 형태로 정의되어 있다.
@AllArgsConstructor
@Getter
public abstract class Customer {
protected double baseDiscountRate;
public double getDiscountRate() {
return baseDiscountRate;
}
public abstract int applyDiscount(int price, int deliveryFee);
}
public class GoldCustomer extends Customer {
private int monthlyPoint;
public GoldCustomer(double baseDiscountRate, int monthlyPoint) {
super(baseDiscountRate);
this.monthlyPoint = monthlyPoint;
}
@Override
public int applyDiscount(int price, int deliveryFee) {
int discountedPrice = price;
if (monthlyPoint > 0) {
int pointDiscount = Math.min(discountedPrice, monthlyPoint);
discountedPrice -= pointDiscount;
monthlyPoint -= pointDiscount;
}
discountedPrice *= (1.0 - getDiscountRate());
return discountedPrice + deliveryFee;
}
}
public class VipCustomer extends Customer {
private int freeDeliveryCnt;
public VipCustomer(double baseDiscountRate, int freeDeliveryCnt) {
super(baseDiscountRate);
this.freeDeliveryCnt = freeDeliveryCnt;
}
@Override
public double getDiscountRate() {
return baseDiscountRate + 0.2;
}
@Override
public int applyDiscount(int price, int deliveryFee) {
int discountedPrice = price;
discountedPrice *= (1.0 - getDiscountRate());
if (freeDeliveryCnt > 0) {
freeDeliveryCnt--;
return discountedPrice;
}
return discountedPrice + deliveryFee;
}
}
만약 VipCustomer 클래스가 사라져서 상속이 무의미해질 때, Customer 클래스와 GoldCustomer를 하나로 묶을 수 있다.
@AllArgsConstructor
@Getter
public class Customer {
private double baseDiscountRate;
private int monthlyPoint;
public double getDiscountRate() {
return baseDiscountRate;
}
public int applyDiscount(int price, int deliveryFee) {
int discountedPrice = price;
if (monthlyPoint > 0) {
int pointDiscount = Math.min(discountedPrice, monthlyPoint);
discountedPrice -= pointDiscount;
monthlyPoint -= pointDiscount;
}
discountedPrice *= (1.0 - getDiscountRate());
return discountedPrice + deliveryFee;
}
}
'리팩토링' 카테고리의 다른 글
[리팩토링] 악취 16 : 임시 필드 * (0) | 2023.02.06 |
---|---|
[리팩토링] 악취 15 : 추측성 일반화 (0) | 2023.02.04 |
[리팩토링] 악취 13 : 반복문 (0) | 2023.01.10 |
[리팩토링] 악취 11 : 기본형 집착 (2) (0) | 2023.01.02 |
[리팩토링] 악취 11 : 기본형 집착 (1) (0) | 2023.01.02 |