스프링 예제 - 주문 할인 도메인

인프런 스프링 핵심 원리 - 기본편 수강 중

비즈니스 요구사항 설계

  • 주문과 할인 정책
    • 회원은 상품 주문 가능
    • 회원 등급에 따른 할인 정책 적용
    • 할인 정책: 모든 VIP에 1000원 고정 금액 할인
    • 할인 정책은 변경 가능성이 높으며 아직 미정

주문 할인 도메인 설계

주문 도메인 관계 및 역할

그림1

  1. 주문 생성:
    클라이언트가 주문 생성 요청

  2. 회원 조회:
    주문 서비스가 할인을 위해 회원 저장소에서 회원 조회

  3. 할인 적용:
    주문 서비스가 회원 등급에 따른 할인 여부 할인 정책에 위임

  4. 주문 결과 반환:
    주문 서비스가 할인 결과를 포함한 주문 결과 반환

역할과 구현을 분리해서 유연하게 변경할 수 있도록 한다. 실제로는 주문 데이터를 DB에 저장하지만 생략하고 결과만 반환

주문 도메인 클래스 다이어그램

그림2

그림3

그림4

회원을 메모리가 아닌 DB에서 조회하고 정률 할인 정책으로 바뀌더라도 주문 서비스를 변경할 필요가 없다

할인 도메인 개발

할인 정책 인터페이스

public interface DiscountPolicy {
    //@return 할인 대상 금액
    int discount(Member member, int price);
}

정액 할인 정책 구현체

public class FixDiscountPolicy implements DiscountPolicy{

    private int discountFixAmount = 1000;

    @Override
    public int discount(Member member, int price) {
        if(member.getGrade() == Grade.VIP){
            return discountFixAmount;
        }
        else{
            return 0;
        }
    }
}
  • VIP만 할인

주문 도메인 개발

주문 엔티티

public class Order {
    private Long memberId;  //long은 null값을 넣을 수 없음
    private String itemName;
    private int itemPrice;
    private int discountPrice;

    public Order(Long memberId, String itemName, int itemPrice, int discountPrice) {
        this.memberId = memberId;
        this.itemName = itemName;
        this.itemPrice = itemPrice;
        this.discountPrice = discountPrice;
    }

    public int calculatePrice(){
        return itemPrice - discountPrice;
    }

    public Long getMemberId() {
        return memberId;
    }

    public void setMemberId(Long memberId) {
        this.memberId = memberId;
    }

    public String getItemName() {
        return itemName;
    }

    public void setItemName(String itemName) {
        this.itemName = itemName;
    }

    public int getItemPrice() {
        return itemPrice;
    }

    public void setItemPrice(int itemPrice) {
        this.itemPrice = itemPrice;
    }

    public int getDiscountPrice() {
        return discountPrice;
    }

    public void setDiscountPrice(int discountPrice) {
        this.discountPrice = discountPrice;
    }

    @Override
    public String toString() {
        return "Order{" +
                "memberId=" + memberId +
                ", itemName='" + itemName + '\'' +
                ", itemPrice=" + itemPrice +
                ", discountPrice=" + discountPrice +
                '}';
    }
}
  • 주문에 필요한 멤버ID, 품명, 가격, 할인 가격 선언
  • 생성자, getter 및 setter

주문 서비스 인터페이스

public interface OrderService {
    Order createOrder(Long memberId, String itemName, int itemPrice);
}

주문 서비스 구현

public class OrderServiceImpl implements OrderService{

    private final MemberRepository memberRepository = new MemoryMemberRepository();
    private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
    @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);
    }
}

실행 - OrderAPp

public class OrderApp {
    public static void main(String[] args) {
        MemberService memberService = new MemberServiceImpl();
        OrderService orderService = new OrderServiceImpl();

        Long memberId = 1L;
        Member member = new Member(memberId, "memberA", Grade.VIP);
        memberService.join(member);

        Order order = orderService.createOrder(memberId, "itemA", 10000);

        System.out.println("order = " + order);
        System.out.println("order.calculatePrice = " + order.calculatePrice());
    }
}

주문 할인 정책 테스트

public class OrderServiceTest {
    MemberService memberService = new MemberServiceImpl();
    OrderService orderService = new OrderServiceImpl();

    @Test
    void createOrder(){
        Long memberId = 1L;
        Member member = new Member(memberId, "memberA", Grade.VIP);
        memberService.join(member);

        Order order = orderService.createOrder(memberId, "itemA", 10000);
        Assertions.assertThat(order.getDiscountPrice()).isEqualTo(1000);

    }
}

[참조] 인프런 스프링 핵심 원리 - 기본편 - 링크

끝!