거짓 중복 발생 사례
상품의 정가를 나타내는 Regular Price 를 정의해봅시다.
public class RegularPrice {
private static final int MIN_AMOUNT = 0;
private final int value;
RegularPrice(final int amount) {
if (amount < MIN_AMOUNT) throw new IllegalArgumentException("가격은 0원 이상이어야 합니다.");
this.value = amount;
}
}
일반 할인, 여름 할인을 책임지는 클래스를 정의해봅시다.
@Getter
public class RegularDiscountedPrice {
private static final int MIN_AMOUNT = 0;
private static final int DISCOUNT_AMOUNT = 4_000;
private final int value;
public RegularDiscountedPrice(final RegularPrice regularPrice) {
int discountedAmount = regularPrice.getValue() - DISCOUNT_AMOUNT;
if (discountedAmount < MIN_AMOUNT) discountedAmount = MIN_AMOUNT;
this.value = discountedAmount;
}
}
@Getter
public class SummerDiscountedPrice {
private static final int MIN_AMOUNT = 0;
private static final int DISCOUNT_AMOUNT = 4_000;
private final int value;
public SummerDiscountedPrice(RegularPrice regularPrice) {
int discountedAmount = regularPrice.getValue() - DISCOUNT_AMOUNT;
if (discountedAmount < MIN_AMOUNT) discountedAmount = MIN_AMOUNT;
this.value = discountedAmount;
}
}
RegularDiscountedPrice, SummerDiscountedPrice 를 보면 다음과 같은 생각을 할 수 있습니다.
두 클래스의 표현과 행위가 같다
=> 중복이 발생했다.
=> DRY 원칙 위배
DRY 원칙
Don't Repeat Yourself
반복을 피해라.
잘못된 DRY 원칙 적용
RegularDiscountedPrice 와 표현과 생성 로직이 같으므로 상속을 받아 중복 제거를 시도합니다.
@Getter
public class SummerDiscountedPrice extends RegularDiscountedPrice {
public SummerDiscountedPrice(RegularPrice regularPrice) {
super(regularPrice);
}
}
- 표현 (MIN_AMOUNT, value) 제거
- 생성 로직 제거
트레이드 오프로 RegularDiscountedPrice- SummerDiscountedPrice 간 강한 결합이 생겼습니다.
클래스 다이어그램으로 표현해봅시다.
강결합으로 일반 할인의 변화에 여름 할인이 영향을 받게되었습니다.
그러나 추후에 여름 할인 정책이 바뀌었습니다.
"여름 학인 가격은 4,000원 고정 할인이 아닌 5% 정률 할인으로 한다."
어떻게 할까요?
상속을 다시 제거하고 클래스를 정의해야합니다.
@Getter
public class SummerDiscountedPrice {
private static final int MIN_AMOUNT = 0;
private static final int DISCOUNT_RATE = 5;
private final int value;
public SummerDiscountedPrice(RegularPrice regularPrice) {
int discountedAmount = regularPrice.getValue() * (100 - DISCOUNT_RATE);
if (discountedAmount < MIN_AMOUNT) discountedAmount = MIN_AMOUNT;
this.value = discountedAmount;
}
}
개념이 다르고 형태만 같다면 거짓 중복이다.
RegularDiscountedPrice 와 SummerDiscountedPrice 는 초기에 같은 멤버 변수, 생성자를 가졌습니다.
그래서 중복이라고 착각하기 쉽습니다.
RegularDiscountedPrice, SummerDiscountedPrice 를 도메인 관점에서 자연어로 풀어봅시다.
일반 할인 가격, 여름 할인 가격
둘은 서로 다른 개념입니다.
비슷한 형태와 행위를 가졌더라도 개념이 다르다면 중복을 허용해야합니다.
'JVM > Java' 카테고리의 다른 글
[Java] Guava - MultiMap , BiMap (0) | 2024.07.14 |
---|---|
[Java] Generic vs WildCard (2) | 2024.01.07 |
[Java] Enum 에는 equals 대신 == 을 써라 (0) | 2023.11.22 |
[Java & Kotlin] Stream (1) | 2023.10.09 |
[Java] SpringBoot 없이 Yaml config 로드하기 (feat.SnakeYaml) (0) | 2023.09.15 |