새로운 할인 정책 개발
저번 예제에서는 고정 할인을 해주었다. 하지만 기획자가 새로운 할인 정책을 해달라고 했다고 가정해보자.
고정 할인이 아닌 10% 할인이다.
차분하게 생각해보면 구현채만 바꾸면 된다.
RateDiscountPolicy 구현
public class RateDiscountPolicy implements DiscountPolicy {
private int discountPercent = 10;
@Override
public int discount(Member member, int price) {
if (member.getGrade() == Grade.VIP) {
return price * discountPercent / 100;
} else {
return 0;
}
}
}
간단하게 Test 해보기
public class RateDiscountPolicyTest {
RateDiscountPolicy discountPolicy = new RateDiscountPolicy();
@Test
@DisplayName("VIP는 10% 할인이 적용되어야 한다.")
void vip_o(){
Member member = new Member(1L, "memberVIP", Grade.VIP);
int discount = discountPolicy.discount(member, 10000);
Assertions.assertThat(discount).isEqualTo(1000);
}
@Test
@DisplayName("VIP가 아니면 할인이 적용되지 않아야 한다.")
void vip_x() {
Member member = new Member(2L, "memberBASIC", Grade.BASIC);
int discount = discountPolicy.discount(member, 10000);
Assertions.assertThat(discount).isEqualTo(0);
}
}
둘다 통가된 모습을 볼 수 있다.
새로운 할인 정책 적용과 문제점
할인 정책을 바꿀려면 어떻게 해야 할까?
저번시간에 구현한 OrderServiceImpl에서 FixDiscountPolicy()를 RadteDiscountPolicy()로 변경하면 된다.
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository = new MemoryMemberRepository();
// private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
@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 코드를 고쳐야 한다.
문제점
OCP, DIP 같은 객체지향 설계 원칙을 충실히 준수하지 못했다.
- DIP 부분은 주문서비스 클라이언트( OrderServiceImpl )는 DiscountPolicy 인터페이스에 의존하면서 DIP를 지킨 것 같아 보인다. 하지만 클래스 의존관계를 분석해보면 답이 나온다. 인터페이스 뿐만 아니라 구현 클레스에도 의존하고 있다. -> FixDiscountPolicy , RateDiscountPolicy
- OCP는 변경하지 않고 확장할 수 있다고 했다. 하지만 지금 코드는 변경하려면 클라이언트 코드에 영향을 준다.
결국 지금 까지 구현했던 코드들은 위의 그림처럼 구현체에도 의존을 하고 있다. DIP와 OCP를 위반하고 있다.
어떻게 문제를 해결할 수 있을까?
간단하게 이렇게 바꾸면 된다. 즉 인터페이스에만 의존하도록 코드를 변경하면 된다.
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository = new MemoryMemberRepository();
// private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
private 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);
}
}
이렇게 바꾸고 코드를 실행하면 당연히 NPE(null pointer exception)이 발생한다.
이 문제를 해결하려면 누군가가 클라이언트인 OrderServiceImpl 에 DiscountPolicy 의 구현 객체를 대신 생성하고 주입해주어야 한다.
스프링 핵심 원리 - 기본편 - 인프런 | 강의
스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., - 강의 소개 | 인프런...
www.inflearn.com
'BackEnd > 스프링 핵심 원리 - 기본편' 카테고리의 다른 글
좋은 객체 지향 설계의 5가지 원칙의 적용 (0) | 2023.01.28 |
---|---|
관심사의 분리 (1) | 2023.01.28 |
스프링 핵심 원리 이해 1 - 예제 만들 (0) | 2023.01.28 |
좋은 객체 지향 설계의 5가지 원칙(SOLID) (0) | 2023.01.27 |
좋은 객체 지향 프로그래밍이란? (0) | 2023.01.27 |