주문

먼저 필요한 요구사항을 정리해보자

  • 사용자가 주문을 한다.
    • 주문에는 한 종류 이상의 메뉴가 있어야 한다.
    • 주문 가능 메뉴만 주문이 가능하다.
  • 사용자가 주문을 취소 한다.
    • 주문 취소는 대기 상태에서만 가능하다.
  • 사용자가 자신의 주문 목록을 조회 한다.
  • 사용자가 자신의 주문을 조회 한다.
  • 주문의 상태는 대기/준비중/배달 이렇게 존재한다.

기능을 만들자

전달할 메세지를 만들고 그에 필요한 속성을 만든다.
여기서 메세지를 전달하기 위해 메서드를 호출하는 것이고 객체의 속성은 필드가 된다.
객체를 만들때 무작정 필드 만들고 메서드 만들기 보다 전달하려는 메세지를 먼저 생각해보자.


주문 도메인

주문 생성

주문이 생성되기 위해 주문자, 주문 상품 목록, 배송 정보가 필요하다.

public class Order {
  public Order(Orderer orderer, List<OrderItem> orderItems, DeliveryInfo deliveryInfo) {
  }
}
주문 객체에 필요한 상태들을 추가하자.

주문에는 주문자, 주문 상품들, 배달정보, 주문 상태가 필요하다
주문 상태에는 대기, 준비중, 배달중, 배달됨, 취소가 있다.

public class Order {
  private Long id;
  private Orderer orderer;
  private List<OrderItem> orderItems;
  private DeliveryInfo deliveryInfo;
  private Status status;

  public Order(Orderer orderer, List<OrderItem> orderItems, DeliveryInfo deliveryInfo) {
  }
  enum Status {
    WAITING, PREPARING, DELIVERING, DELIVERED, CANCELED
  }
}
주문 객체 생성

주문이 생성 될 때 주문의 상태는 대기중이다.

public class Order {
  private Long id;
  private Orderer orderer;
  private List<OrderItem> orderItems;
  private DeliveryInfo deliveryInfo;
  private Status status;

  /** 주문 생성 */
  public void order(Orderer orderer, DeliveryInfo deliveryInfo, OrderItem... orderItems) {
    this.orderer = orderer;
    this.orderItems = orderItems;
    this.deliveryInfo = deliveryInfo;
    this.status = Status.ORDERED;     // <-- 주문 생성 시 대기중 상태로 생성됨
  }
  enum Status {
    WAITING, PREPARING, DELIVERING, DELIVERED, CANCELED
  }
}
주문 취소

주문 취소는 대기중 상태일때만 가능하다.

public class Order {
  // ...

  /** 주문 취소 */
  public void cancel() {
    if (enableOrderCancel()) {
      status = Status.CANCELED;
    }
    throw new RuntimeException();
  }

  /** 주문 취소 가능 여부 */
  private boolean enableOrderCancel() {
    return Status.ORDERED.equals(status);
  }

  enum Status {
    WAITING, PREPARING, DELIVERING, DELIVERED, CANCELED
  }
}

도메인 이벤트

주문이 생성되면? 가게에 알려줘야한다.
주문과 가게는 다른 도메인으로 주문에서 가게에 의존 관계가 생기면 결합도가 높아진다.
이를 해결하기 위해 주문 생성시 주문 생성 이벤트를 발행하고 가게 서비스에서 그 이벤트를 구독하여 후속 작업을 하게 되면?
주문과 가게의 의존 관계가 생기지 않아 결합도를 낮출 수 있다.

레포지토리

public interface OrderRepository {
  Order findById(long id);
  Order save(Order order);
}
패키지

주문 도메인과 주문 레포지토리를 도메인 패키지에 넣는다.

└── src
    ├── main
    │   ├── java
    │   │   └── com.example.dddstudy
    │   │       └── DddStudyApplication.java
    │   │       └── order
    │   │           └── domain
    │   │               ├── Order.java
    │   │               ├── Orderer.java
    │   │               ├── OrderItem.java
    │   │               ├── DeliveryInfo.java
    │   │               └── OrderRepository.java