순진 개발자가 정말 객체지향 설계 원칙을 잘 준수했는지 확인해보자. 이번에는 주문 금액의 %를 할인해주는 새로운 정률 할인 정책을 추가하자.
public class RateDiscountPolicy implements DiscountPolicy{
private final int discountPercent = 10;
@Override
public int discount(Member member, int price) {
if (member.getGrade() == Grade.VIP) {
return price * discountPercent / 100;
} else {
return 0;
}
}
}
import static org.assertj.core.api.Assertions.*;
class RateDiscountPolicyTest {
RateDiscountPolicy discountPolicy = new RateDiscountPolicy();
@Test
@DisplayName("VIP는 10% 할인이 적용되어야 한다.")
void vip_o() {
// given
Member member = new Member(1L, "memberVIP", Grade.VIP);
// when
int discount = discountPolicy.discount(member, 10000);
// then
assertThat(discount).isEqualTo(1000);
}
@Test
@DisplayName("VIP가 아니면 할인이 적용되지 않아야 한다.")
void vip_x(){
// given
Member member = new Member(1L, "memberBASIC", Grade.BASIC);
// when
int discount = discountPolicy.discount(member, 10000);
// then
assertThat(discount).isEqualTo(0);
}
}
// private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
OrderServiceImpl
의 코드를 고쳐야 한다.OrderServiceImp
)은 DiscountPolicy
인터페이스에 의존하면서 DIP를 지킨 것 같이 보일 뿐.DiscountPolicy
FixDiscountPolicy
, RateDiscountPolicy
클래스 다이어그램으로 의존 관계를 분석해보자
DiscountPolicy
인터페이스만 의존한다고 생각했다.OrderServiceImpl
이 DiscountPolicy
인터페이스 뿐만 아니라 FixDiscountPolicy
인 구체 클래스도 함께 의존하고 있다.FixDiscountPolicy
를 RateDiscountPolicy
로 변경하는 순간 OrderServiceImpl
의 소스코드도 함께 변경해야 한다.OrderServiceImpl
은 DiscountPolicy
의 인터페이스 뿐만 아니라 구체 클래스도 함께 의존한다.private DiscountPolicy discountPolicy;
OrderServiceImpl
에 DiscountPolicy
의 구현 객체를 대신 생성하고 주입해주어야 한다.