[Spring] 03-1. 새로운 할인 정책 개발

지찬우·2022년 12월 23일
0

Spring

목록 보기
10/27
post-thumbnail

이 시리즈는 인프런 강의(김영한 님의 ‘스프링 핵심 원리 - 기본편’)로 공부하며 혼자 기록하고, 사람들과도 공유할 수 있도록 작성하는 글이다. 최대한 추가적인 정보는 공식 홈페이지, 문서를 보며 얻을 예정이다.
(개인적인 생각과 이해가 들어가 있기 때문에 저의 ‘무식함’이 있을 수 있습니다😜 혹시라도 이 글을 보게 되시는 분이 계시다면 잘못된 부분 댓글로 많이 알려주시면 너무 감사하겠습니다!!)

GitHub Repository : https://github.com/jcw1031/spring-core-study


새로운 할인 정책 개발

고정 할인 정책 대신, 정률 할인 정책을 개발해 바꿔보도록 하자.

정률 할인 정책

🛠️ 구현체 개발

discount 패키지에 정률 할인 정책 RateDiscountPolicy를 생성하자.


회원의 등급이 VIP인 경우에 상품 금액의 10%를 할인해 준다고 한다. 고정 할인 정책과 비슷하지만, VIP인 경우에 상품 가격의 10%를 return 한다.


🧪 테스트 코드 작성

IntelliJ에서 해당 구현체의 테스트를 단축키를 통해 바로 생성할 수 있다. 아래의 단축키를 사용한다.

MacOS : + + T
Windows : Ctrl + Shift + T


그럼 다음과 같은 설정 창이 뜨는데, 따로 설정은 안 해줘도 되고 그냥 바로 OK를 누르면 된다.


자동으로 test/java/Group이름.core 패키지에 discount 패키지와 RateDiscountPolicyTest가 생성된다. 이 테스트에서는 정률 할인 정책 구현체가 필요하니 RateDiscountPolicy를 생성한다.


@Test 어노테이션을 사용하고, @DisplayName 어노테이션을 사용하는데 JUnit5에서 지원하는 기능으로, 테스트의 이름을 한글로 출력되게 할 수 있다.


테스트를 진행할 함수를 만들어 준다.


임시로 VIP 회원을 생성하고 정률 할인 정책의 discount()를 사용해 할인 금액을 discount 변수로 받아온다. 마지막으로 Assertions를 사용하여 할인 금액이 맞는지 확인한다.(10000원의 10%는 1000원이므로 isEqualTo(1000))


실행해 보면 역시 성공한다.


이제는 반대로 VIP가 아닌 경우에 할인이 적용이 안 되는지 확인해 보겠다.


BASIC 회원을 생성하는 것을 제외하고, 나머지는 이 전과 동일하다.


실행해 보면 ‘할인 금액이 1000원이어야 한다’라고 코드를 작성했기 때문에 당연히 실패다. 친절하게 console에 기대되었던 값과 실제 값을 출력해 준다. isEqualTo()의 매개변수를 0으로 변경하면 성공한다.


static import를 사용하면 Assertions를 매번 입력하지 않아도 된다!

아래와 같이 Assertions에 커서를 두고 quick-fixes 기능을 사용하여 static import로 바꿔준다.


그럼 import static 하고 Assertions가 추가된다.


Assertions를 입력하지 않아도 돼서 깔끔하다.


새로운 할인 정책 적용

새로 개발한 정률 할인 정책을 적용해 보도록 하자. 주문 서비스에서 FixDiscountPolicy 대신 RateDiscountPolicy를 생성해야 한다.


문제점❗️

현재 역할과 구현을 잘 분리하였고 다형성도 활용하고 인터페이스와 구현 객체를 분리하였다. 하지만 OCP와 DIP를 준수하지 못했다. 왜냐하면 주문 서비스 클라이언트가 할인 정책 인터페이스뿐만 아니라 구현 클래스도 의존하고 있기 때문이다. FixDiscountPolicy에서 RateDiscountPolicy로 변경할 때 주문 서비스 클라이언트도 영향을 받고 있기 때문에 OCP를 위반한 것이다.

우리가 기대한 의존관계는 주문 서비스 구현체가 할인 정책 인터페이스만을 의존해야 한다.


하지만 실제로는 할인 정책 인터페이스에도 의존하고, 구현체에도 의존하고 있다. 이는 DIP를 위반하는 것이다! 그래서 할인 정책 구현체를 변경할 때 주문 서비스의 코드도 변경해야 하기 때문에 OCP도 위반한다.


해결 방안❗️

그럼 어떻게 해결해야 할까?

DIP를 위반하지 않도록 주문 서비스가 인터페이스에만 의존하도록 변경해야 한다. 아래의 코드처럼 변경해야 인터페이스에만 의존하게 되는 것이다.


하지만 구현체가 없기 때문에 실행을 하게 되면 NullPointerException이 발생한다.

따라서 ‘누군가’가 주문 서비스 클라이언트에 할인 정책 구현 객체를 대신 생성하고 주입해 주어야 한다!


다음 시간에는 관심사를 분리하여 그 ‘누군가’를 개발해 보도록 하겠다.

profile
좋은 개발자가 되자.

0개의 댓글