[Java] 주문과 할인 도메인(2)

JJoSuk·2023년 5월 30일
0

본 프로젝트 자료는 김영한님 스프링 핵심 원리 - 기본편을 참고로 제작됐습니다.

주문과 할인 도메인 설계

  • 주문과 할인 정책
    • 회원은 상품을 주문할 수 있다.
    • 회원 등급에 따라 할인 정책을 적용할 수 있다.
    • 할인 정책은 모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용해달라. (나중에 변경 될 수 있다.)
    • 할인 정책은 변경 가능성이 높다. 회사의 기본 할인 정책을 아직 정하지 못했고, 오픈 직전까지 고민을 미루고 싶다. 최악의 경우 할인을 적용하지 않을 수 도 있다. (미확정)

현재 상황은 VIP한테 고정으로 무엇을 주문하든 고정으로 1000원을 할인하고자 하는 정책을 실행하고자 하나, 확정이 아니라 언제든 변경될 수 있는 상황이다.

현재 주문과 할인 정책을 바탕으로 설계된 전체 도메인이다

현재 확정된 사항이 없기 때문에 일단 주문이 들어온대로 설계를 진행하되, 추후 DB나 정률 할인 정책으로 바뀔 수 있기 때문에 상황을 대비하여 제작해야 한다.


주문과 할인 도메인 개발

  • 할인 정책 인터페이스
package hello.core.discount;

import hello.core.member.Member;

public interface DiscountPolicy {

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

기본 할인 인터페이스 제작


  • 정액 할인 정책 구현체
package hello.core.discount;

import hello.core.member.Grade;
import hello.core.member.Member;

public class FixDiscountPolicy implements DiscountPolicy {

    // VIP 한정 상시 1000원 할인
    private int discountFixAmount = 1000;

    // VIP 면 1000원 아니면 0원
    @Override
    public int discount(Member member, int price) {
        if(member.getGrade() == Grade.VIP) {
            return discountFixAmount;
        } else {
            return 0;
        }
    }
}

VIP면 1000원 고정 할인, else 아니면 할인 0원


  • 주문 엔티티
package hello.core.order;

public class Order {

    private Long memberId;
    private String itemName;
    private int itemPirce;
    private int discountPrice;

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

    // 상품 금액 빼기 1000원 금액
    public int calculatePrice() {
        return itemPirce - 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 getItemPirce() {
        return itemPirce;
    }

    public void setItemPirce(int itemPirce) {
        this.itemPirce = itemPirce;
    }

    public int getDiscountPrice() {
        return discountPrice;
    }

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

    @Override
    public String toString() {
        return "Order{" +
                "memberId=" + memberId +
                ", itemName='" + itemName + '\'' +
                ", itemPirce=" + itemPirce +
                ", discountPrice=" + discountPrice +
                '}';
    }
}

  • 주문 서비스 인터페이스
package hello.core.order;

public interface OrderService {
    // 최종 오더의 결과 값을 반영하는 로직
    Order createOrder(Long memberId, String itemName, int itemPrice);
}

  • 주문 서비스 구현체
package hello.core.order;

import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
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();
    @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);
    }
}

주문 생성 요청이 오면, 회원 정보를 조회하고, 할인 정책을 적용한 다음 주문 객체를 생성해서 반환한다. 메모리 회원 리포지토리와, 고정 금액 할인 정책을 구현체로 생성한다.


주문과 할인 도메인 실행과 테스트

  • 주문과 할인 정책 실행
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.toString());
    }
}

현재 고객의 주문을 받을 수 없는 상태이기에, 임의로 1번 VIP 손님의 주문과 할인이 제대로 들어갔는지 확인 해본다.

/Library/Java/JavaVirtualMachines/jdk-11.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=49800:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/joseoghwan/Desktop/study/core/out/production/classes:/Users/joseoghwan/Desktop/study/core/out/production/resources:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-starter/2.7.12/a5f6a95e4e4a50cfaf0f14c86240d8be49637141/spring-boot-starter-2.7.12.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-autoconfigure/2.7.12/5bb8661bba72f7ca353ae486ccb06285f0ed84eb/spring-boot-autoconfigure-2.7.12.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot/2.7.12/888c3545dc3c6ca791753c7ad621a2d03f222732/spring-boot-2.7.12.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-starter-logging/2.7.12/b6590492b4d92baebb4ac7c1b5db11fc3488e347/spring-boot-starter-logging-2.7.12.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/jakarta.annotation/jakarta.annotation-api/1.3.5/59eb84ee0d616332ff44aba065f3888cf002cd2d/jakarta.annotation-api-1.3.5.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/org.springframework/spring-core/5.3.27/ff5e35f2d4f72d22c476ff9b7bce1de25c980ebd/spring-core-5.3.27.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/org.yaml/snakeyaml/1.30/8fde7fe2586328ac3c68db92045e1c8759125000/snakeyaml-1.30.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/org.springframework/spring-context/5.3.27/251162aa2fe5cb374a482ae87fa6e8e8e747d72/spring-context-5.3.27.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-classic/1.2.12/d4dee19148dccb177a0736eb2027bd195341da78/logback-classic-1.2.12.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-to-slf4j/2.17.2/17dd0fae2747d9a28c67bc9534108823d2376b46/log4j-to-slf4j-2.17.2.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/org.slf4j/jul-to-slf4j/1.7.36/ed46d81cef9c412a88caef405b58f93a678ff2ca/jul-to-slf4j-1.7.36.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/org.springframework/spring-jcl/5.3.27/9698ea7d5361b5e3a27ed08beb7770279bd2397/spring-jcl-5.3.27.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/org.springframework/spring-aop/5.3.27/ecae2962d53c587fd0e405cd60dc8415d1b9e12d/spring-aop-5.3.27.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/org.springframework/spring-beans/5.3.27/46e7d917551ffcc0a104fd971d1fa207b30d7761/spring-beans-5.3.27.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/org.springframework/spring-expression/5.3.27/6225619970e8376df5c3d777610d9d03b977063b/spring-expression-5.3.27.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-core/1.2.12/1d8e51a698b138065d73baefb4f94531faa323cb/logback-core-1.2.12.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.7.36/6c62681a2f655b49963a5983b8b0950a6120ae14/slf4j-api-1.7.36.jar:/Users/joseoghwan/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-api/2.17.2/f42d6afa111b4dec5d2aea0fe2197240749a4ea6/log4j-api-2.17.2.jar hello.core.OrderApp
order = Order{memberId=1, itemName='itemA', itemPirce=10000, discountPrice=1000}

Process finished with exit code 0

정상적으로 출력되는걸 확인할 수 있다. 하지만 좋은 테스트 방법이 아니라 JUnit 테스트를 사용하자.


주문 할인 정책 테스트

package hello.core.test;

import hello.core.member.Grade;
import hello.core.member.Member;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.order.Order;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

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);
    }
}

오류가 발생하지 않는다면 잘 작동된거라 보면 될 듯 싶다. 다음 내용은 현 고정 할인 정책이 아닌 정률 할인 정책으로 수정하며, 좋은 객체 지향 설계의 5가지 원칙을 제대로 활용해보고자 한다.

profile
안녕하세요

0개의 댓글