새로운 할인 정책 적용과 문제점

myeonji·2022년 2월 13일
0

Spring

목록 보기
15/22

할인정책(DiscountPolicy) 인터페이스에는
1. FixDiscountPolicy(고정할인)
2. RateDiscountPolicy(정률할인)
라는 구현체가 있다.


< DiscountPolicy > 인터페이스(역할)

public interface DiscountPolicy {

    /**
     * @return 할인 대상 금액
     */
    int discount(Member member, int price);
}

할인정책은 여러가지가 있을 수 있다.
고정할인금액, 정률할인금액, ... 등등 앞으로도 할인방법은 계속 추가될 수 있으니 할인정책이라는 인터페이스를 구현하고 구현체를 만들어 할인정책 방법을 바꿔끼며 사용할 수 있다.

우선, FixDiscountPolicy 할인정책을 사용해보겠다.

< FixDiscountPolicy > 구현체

public class FixDiscountPolicy implements DiscountPolicy {

    private int discountFixAmount = 1000; // 천원 할인

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

위의 할인정책 방법을 사용하기 위해서는
주문 서비스에서 주입 받아야 한다.

< OrderServiceImple >

public class OrderServiceImpl implements OrderService {

    private final MemberRepository memberRepository = new MemoryMemberRepository();
    private final DiscountPolicy discountPolicy = new FixDiscountPolicy();

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

        // 할인은 내 책임이 아님! 할인에 관한건 전부 dicountPolicy에 넘김 (회원 등급, 상품 가격)
        // SRP(단일 책임 원칙) 잘 지켜짐
        int discountPrice = discountPolicy.discount(member, itemPrice);

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

위의 코드처럼

private final DiscountPolicy discountPolicy = new FixDiscountPolicy();

이러한 문장으로 FixDiscountPolicy 구현체를 주입받을 수 있다.

만약 할인정책이 고정할인에서 정률할인으로 바뀐다고 하더라도 구현체만 갈아끼우면 된다.
아래처럼 말이다!

private final DiscountPolicy discountPolicy = new RateDiscountPolicy();

⭐ 하지만!!! 문제점이 있다.

객체지향 설계 원칙 중 OCP, DIP를 잘 지키고 있는가?

를 살펴보면 그렇지 않다는 것을 알 수 있다.

  • OCP : 확장에는 열려있고 변경에는 닫혀있나?
    • 위의 OrderServiceImpl(클라이언트)를 보면, 할인정책을 고정할인->정률할인 으로 변경하고자 할 때, OrderServiceImple(클라이언트) 코드를 변경해야 한다.
    • OCP 위반이다.
  • DIP : 구현체에 의존하지 않고 역할에만 의존하고 있나?
    • OrderServiceImple 를 보면 DiscountPolicy(역할) 뿐만 아니라 FixDiscountPolicy(고정할인 구현체) 또는 RateDiscountPolicy(정률할인 구현체)에도 의존하고 있다.(코드 내에서 해당 구현체 이름이 사용되고 있다(?), 알고있다(?) 라고 이해 하였다.)

💡 DiscountPolicy(인터페이스)에만 의존하도록 설계를 변경하자!

OrderServiceImpl에서 할인정책 인터페이스인 DiscountPolicy에만 의존하도록 코드를 변경하면,

public class OrderServiceImpl implements OrderService {

    private final MemberRepository memberRepository = new MemoryMemberRepository();
//    private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
//    private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
    private DiscountPolicy discountPolicy; // final은 값을 무조건 할당해야해서 제거, 구현체에 의존하지 않고 역할(인터페이스)에만 의존하는 중

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

        // 할인은 내 책임이 아님! 할인에 관한건 전부 dicountPolicy에 넘김 (회원 등급, 상품 가격)
        // SRP(단일 책임 원칙) 잘 지켜짐
        int discountPrice = discountPolicy.discount(member, itemPrice);

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

위처럼 변경할 수 있다.
"= new FixDiscountPolicy()"를 제거한 것이다.

이렇게 변경함으로써 DIP 위반을 해결하였는데, 이를 실행해보면 NullPointerException이 발생한다.
당연하다, DiscountPolicy는 인터페이스이고, 구현체를 지정해주지 않았는데 실행될 수 없다.

✨ 해결방법 !! -> 관심사의 분리

중요하니까 따로 다루기..

0개의 댓글