package hello.core.discount;
import hello.core.member.Grade;
import hello.core.member.Member;
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;
}
}
}
RateDiscountPolicyTest
package hello.core.discount;
import hello.core.member.Grade;
import hello.core.member.Member;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;
class RateDiscountPolicyTest {
RateDiscountPolicy rateDiscountPolicy = new RateDiscountPolicy();
@Test
@DisplayName("VIP는 10% 할인이 적용되어야 한다.")
void VIP_할인_성공() {
//given
Member member = new Member(1L, "memberVIP", Grade.VIP);
//when
int discount = rateDiscountPolicy.discount(member , 10000);
//then
assertThat(discount).isEqualTo(1000);
}
@Test
@DisplayName("VIP가 아니면 할인이 적용되지 않아야 한다.")
void VIP_할인_실패(){
//given
Member member = new Member(1L, "memberBASIC", Grade.BASIC);
//when
int discount = rateDiscountPolicy.discount(member , 10000);
//then
assertThat(discount).isEqualTo(0);
}
}
문제점
클라이언트인 OrderServiceImpl 코드를 고쳐야한다.
package hello.core.order;
import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import hello.core.member.Member;
import hello.core.member.MemberRepository;
import hello.core.member.MemoryMemberRepository;
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);
}
}
역할과 구현을 충실한게 분리 했다.
다형성도 활용하고 , 인터페이스와 구현 객체를 분리했다.
OCP , DIP 같은 객체지향 설계 원칙을 충실히 준수했다.
그렇게 보이지만 사실은 아니다.
DIP : 주문 서비스 클라이언트(OrderServiceImpl)는 DiscountPolicy에 의존하면서 DIP를 지킨것 같지만
클래스 의존관계를 분석해 보면 , 추상(인터페이스)뿐만 아니라 구체(구현) 클래스에도 의존 하고 있다.
추상(인터페이스) 의존 : DiscountPolicy
구체(구현) 클래스 : FixDiscountPolicy , RateDiscountPolicy
OCP : 코드를 변경하지 않고 확장해야 하는데 지금 코드는 기능을 확장해서 변경하면 클라이언트 코드에 영향을 준다. 따라서 OCP를 위반한다.
어떻게 문제를 해결할 수 있을까??
DIP를 위반하지 않도록 인터페이스에만 의존하도록 의존관계를 변경하면 된다.
OrderServiceImpl
package hello.core.order;
import hello.core.discount.DiscountPolicy;
import hello.core.member.Member;
import hello.core.member.MemberRepository;
import hello.core.member.MemoryMemberRepository;
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository = new MemoryMemberRepository();
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가 발생한다.
해결방안
이 문제를 해결하려면 누군가가 클라이언트인 OrderServiceImpl에 DiscountPolicy의 구현 객체를 대신 생성하고 주입 해주어야 한다.
객체 지향 원리 적용 - 새로운 할인 정책 개발 및 적용 과 문제점
주문과 할인 도메인 개발 및 테스트
write-read.tistory.com
RateDiscountPolicy
RateDiscountPolicyTest
문제점
클라이언트인 OrderServiceImpl 코드를 고쳐야한다.
어떻게 문제를 해결할 수 있을까??
DIP를 위반하지 않도록 인터페이스에만 의존하도록 의존관계를 변경하면 된다.
OrderServiceImpl
객체 지향 원리 적용 - 관심사의 분리
write-read.tistory.com
스프링 핵심 원리 - 기본편 - 인프런
스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다. 초급 프레임워크 및 라이브러리 웹 개발 서버 개발 Back-End Spring 객체지향 온
www.inflearn.com
'스프링 핵심 원리 > 스프링 핵심 원리 이해' 카테고리의 다른 글