⇒ 인터페이스를 만들고 구현체를 언제든지 갈아 끼울 수 있어야 한다 !
⇒ 앞에서 배운 객체 지향 설계 방법을 이용해서 비즈니스 요구 사항대로 설계해보자
public interface DiscountPolicy {
/**
* @return 할인 대상 금액
*/
int discount(Member member, int price);
}
public class FixDiscountPolicy implements DiscountPolicy {
/* VIP면 1000원 할인, 아니면 할인 없음 */
private int discountFixAmount = 1000; // 1000원 할인
@Override
public int discount(Member member, int price) {
if (member.getGrade() == Grade.VIP) {
return discountFixAmount;
} else {
return 0; // 할인 없어 !
}
}
}
public interface OrderService {
/*
주문 생성
- 회원 ID
- 상품명
- 상품가격
return 주문 결과 반환
*/
Order createOrder(Long memberId, String itemName, int itemPrice);
}
회원 검색을 위해 MemebrRepostitory가 필요함
할인 정책을 위해 DiscountPolicy가 필요함
public class OrderServiceImpl implemets OrderService {
// MemberRepository에서 회원을 찾아야 한다.
private final MemberRepository memberRepository = new MemoryMembreRepository();
// DiscountPolicy에서 할인 정책을 찾는다.
private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
@Override
public Order createOrder(Long memberId, String itemName, int itemPrice) {
/*
Member 대신 Grade를 넣어줘도 된다. 나의 선택이다.
회원을 조회하고, 아이템 가격을 넣어주면 주문 결과를 반환한다.
*/
Member member = memberRepository.findById(memeberId);
int discountPrice = discountPolicy.discount(member, itemPrice);
return new Order(memberId, itemName, itemPrice, discountPrice);
}
}
→ ❗ 설계가 매우 잘된 상황
why? OrderService에서는 할인에 대한 것을 모른다. DiscountPolicy가 할인을 처리한다. → 단일 책임 원칙 준수, 할인에 대한 변경은 할인 쪽에서만 이뤄진다.
// 멤버 서비스
// 주문 서비스
// 멤버 객체 생성 (할인 정책이 적용되었는지 알기위해 Grade.VIP)
// 멤버 회원가입
// 멤버가 itemA(1000원) 주문함
// System.out.println("order = " + order); // 9000
import org.assertj.core.api.Assertions;
// 멤버 서비스
// 주문 서비스
@Test
void createOrder() {
// 멤버 객체 생성 (할인 정책이 적용되었는지 알기위해 Grade.VIP)
// 멤버 회원가입
// 멤버가 itemA(1000원) 주문함
Assertions.assertThat(order.getDiscountPrice()).isEqualTo(1000);
}
✍️ 단위 테스트
스프링이나 컨테이너의 도움없이 자바 코드로만 테스트를 하는 것
다음 시간에는 ~
참고 사이트