Kim-Baek 개발자 이야기

[스프링 핵심원리] 15. 새로운 할인 정책 적용과 문제점 본문

개발/Spring

[스프링 핵심원리] 15. 새로운 할인 정책 적용과 문제점

김백개발자 2021. 10. 5. 20:16
김영한님의 [스프링 핵심 원리] 강의를 정리하고, 내가 생각한 내용까지 정리하는 포스팅

지난번에 새로운 할인 정책을 만들어서 테스트까지 했으니 이제 실제 코드에 적용을 해보는 시간이다.

public class OrderServiceImpl implements OrderService {
  //    private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
      private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
  }

FixDicountPolicy를 RateDiscountPolicy 를 위와같이 적용하면 된다. 이 코드는 어떤 상태라고 생각이 될까?

역할과 구현을 분리한 것은 맞다. 다형성도 지키고 인터페이스와 구현 객체를 분리한 것도 맞다. 그렇다면 가장 중요한 객체지향 설계 원칙은 잘 지킨 것이라고 할 수 있을까?

DIP 원칙을 다시 기억해보자.  "추상화에 의존해야지, 구체화에 의존하면 안된다" 라는 원칙이다. 구현 클래스에 의존하지 말고 인터페이스에 의존하라는 뜻이다. 여기서 OrderServiceImpl 은 DiscountPolicy를 의존하고 있으니 추상화에 의존하고 있다고 할 수 있을까?

그렇지 않다. 추상화에도 의존을 하지만, RateDiscountPolicy 와 같은 구현 클래스에도 의존을 하고 있기 때문이다. 이전부터 계속 봐왔던 문제라고 할 수 있다.

그리고 OCP를 지키고 있을까? 변경하지 않고 확장이 되어야한다고 했는데, 정책이 변경되면서 우리는 클라이언트 코드가 변경이 되고 직접 구현객체를 수정해줬다.

우리가 만들면서 기대한 의존관계는 다음과 같다. 아래의 구현 객체를 의존하지 않고 추상화된 인터페이스만 의존하는 것이다. 하지만 실제로는 어떤가?

실제로는 인터페이스와 구현 클래스 모두를 의존하고 있는 모습이라는 것을 알 수 있다. 그리고 정책을 변경하면 어떻게 될까?

OrderServiceImple이 구현클래스에도 의존하고 있기 때문에, 소스코드의 변경이 필요한 모습이다. DIP 와 OCP가 모두 안지켜지고 있다는 것을 알 수 있다.

그러면 어떻게 해결할 수 있을까? 구현클래스에 의존하지 않고 추상화된 인터페이스에만 의존하면 되지 않을까?

이 모습이 되도록 코드를 한번 변경해보자

public class OrderServiceImpl implements OrderService {
      //private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
      private DiscountPolicy discountPolicy;
}

이렇게 코드를 변경하면 우리가 원했던 의존관계가 나온다. 그런데 실제로 실행해보면 자주보던 Null Pointer Exception이 나오는 것을 볼 수 있다. 

이것을 해결하려면 누군가가 OrderServiceImpl 에 DisCountPolicy 의 구현객체를 대신 생성하고 주입해줘야 한다. 다음부터는 이것을 만들어 보겠다.

 


반응형
Comments