새로운 할인 정책 개발

2023. 7. 9. 19:58Spring/[inflearn]스프링 핵심 원리 - 기본편

◎ 요구 사항 변경 

-> 기존에 적용하던 할인 정책은 VIP 등급인 모든 회원에게 1000원을 할인해주는 정액할인 정책이다. 여기에서 주문 금액당 할인을 해주는 정률할인 정책으로 변경한다.

 

-> RateDiscountPolicy 클래스 생성(정률 할인 정책 구현 클래스)

/**
 * <정률 할인 정책>
 * VIP인 고객의 주문 금액의 10% 할인 적용
 */
public class RateDiscountPolicy implements DiscountPolicy{
    private int discountPercent = 10; // 10% 할인

    @Override
    public int discount(Member member, int price) {
        if (member.getGrade() == Grade.VIP) {
            return price * discountPercent / 100;
        }else {
            return 0;
        }
    }
}

 

-> 할인 정책 테스트

/**
 * <정률 할인 정책 테스트>
 */
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, "memberVIP", Grade.BASIC);

        // when
        int discount = discountPolicy.discount(member, 10000);

        // then
        assertThat(discount).isEqualTo(0);
    }
}

 

-> 결과

 

◎ 문제점

-> 현재 할인 정책 구현 클래스로 FixDiscountPolicy와 RateDiscountPolicy가 있다. 이 둘 중 하나를 선택하여 적용을 하려면 OrderServiceImpl 클래스에서 코드를 직접 수정해야 한다.

public class OrderServiceImpl implements OrderService{

    //회원 저장소와 할인 정책을 의존할 때 각 인터페이스의 구현 클래스에 의존한다.
    private final MemberRepository memberRepository = new MemoryMemberRepository();
    
    // 할인 정책을 변경하려면 이 코드를 직접 수정해야 한다.
    private final DiscountPolicy discountPolicy = new FixDiscountPolicy();

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        int discountPrice = discountPolicy.discount(member, itemPrice);

        return new Order(memberId, itemName, itemPrice, discountPrice);
    }
}

-> 이 코드는 추상(DiscountPolicy 인터페이스)에도 의존하고 구현체(Fix/RateDiscountPolicy)에도 의존하고 있다. 따라서 이 코드는 DIP를 위반한다.

-> 또한 할인정책을 변경하려면 OrderServiceImpl의 코드를 직접 변경해야 한다. 따라서 OCP를 위반한다.

-> 추상에만 의존하도록 의존관계를 변경해야 한다.

 

public class OrderServiceImpl implements OrderService{

    //회원 저장소와 할인 정책을 의존할 때 각 인터페이스의 구현 클래스에 의존한다.
    private final MemberRepository memberRepository = new MemoryMemberRepository();
//    private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
    private final DiscountPolicy discountPolicy;

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        int discountPrice = discountPolicy.discount(member, itemPrice);

        return new Order(memberId, itemName, itemPrice, discountPrice);
    }
}

-> OrderServiceImpl에서 추상에만 의존하도록 코드를 변경했다. 하지만 구현체가 아닌 추상에만 의존한 상태라서 실행을 하면 NPE가 발생한다.

 

-> 이 문제를 해결하기 위해서는 OrderServiceImpl에 DiscountPolicy의 구현 객체를 생성하고 주입하는 역할이 필요하다.

 

 

☆ 참고

[인프런]스프링 핵심 원리 - 기본편