본문 바로가기
개발일지/기타

도메인 모델 패턴과 트랜잭션 스크립트 패턴

2022. 7. 25.

도메인 모델 패턴

엔티티(Entity)가 비즈니스 로직을 가지고 객체 지향의 특성을 적극 활용하는 것을 도메인 모델 패턴이라 한다.

OrderService 의 메서드를 보면 비즈니스 로직이 대부분 엔티티에 있다.

서비스 계층은 단순히 엔티티에 필요한 요청을 위임하는 역할을 한다.

ddd(domain driven design)를 접목시킬 경우 이 방법을 사용한다.

 

트랜잭션 스크립트 패턴

반대로 엔티티에는 비즈니스 로직이 거의 없고 서비스 계층에서 대부분의 비즈니스 로직을 처리하는 것을 트랜잭션 스크립트 패턴이라고 한다.

즉, 하나의 트랜잭션으로 구성된 로직을 단일 함수 또는 단일 스크립트에서 처리하는 구조를 갖는다. 그래서 패턴의 이름이 트랜잭션 스크립트이다.

 

도메인 모델 패턴 예시

// import는 생략
@Entity
@Table(name = "orders")
@Getter @Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Order {

    @Id @GeneratedValue
    @Column(name = "order_id")
    private Long id;

    @ManyToOne(fetch = LAZY)
    @JoinColumn(name = "memder_id")
    private Member member;

    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderItem> orderItems = new ArrayList<>();

    @OneToOne(fetch = LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "delivery_id")
    private Delivery delivery;

    private LocalDateTime orderDate;

    @Enumerated(EnumType.STRING) // 만약에 EnumType 이 ORDINAL 이면 새로운 타입이 추가 되면 숫자가 꼬여서 반드시 STRING으로 해야한다.
    private OrderStatus status; // 주문 상태 [ORDER ,CANDEL]

    public void setMember(Member member){
        this.member = member;
        member.getOrders().add(this);
    }

    public void addOrderItem(OrderItem orderItem){
        orderItems.add(orderItem);
        orderItem.setOrder(this);
    }

    public void setDeliver(Delivery delivery){
        this.delivery = delivery;
        delivery.setOrder(this);
    }

    // ==생성 메서드== //
    // createOrderItem 에서 removeStock 으로 재고를 줄이고 올거다.
    public static Order createOrder(Member member, Delivery delivery, OrderItem... orderItems){
        Order order = new Order();
        order.setMember(member);
        order.setDelivery(delivery);
        for (OrderItem orderItem : orderItems){
            order.addOrderItem(orderItem);
        }
        order.setStatus(OrderStatus.ORDER);
        order.setOrderDate(LocalDateTime.now());
        return order;
    }

    // ==비즈니스 로직== //
    /*
     * 주문 취소
     */
    public void cancel() {
        if(delivery.getStatus() == DeliveryStatus.COMP) {   // 배송 완료이면
            throw new IllegalStateException("이미 배송완료된 상품은 취소가 불가능 합니다.");
        }

        // 배송 완료 아니면 상태를 CANCEL로 바꿈
        this.setStatus(OrderStatus.CANCEL);
        for (OrderItem orderItem: orderItems ) {
            orderItem.cancel();
        }
    }

    // ==조회 로직== //
    /*
    * 전체 주문 가격 조회
    * */
    public int getTotalPrice() {
        int totalPrice = 0;
        for(OrderItem orderItem : orderItems) {
            totalPrice += orderItem.getTotalPrice();
        }

        return totalPrice;

        // 위에 로직을 Replace with sum() 으로 바꾸고 -> inline variable 한 결과이다.
        /*
        return orderItems.stream().
                mapToInt(OrderItem::getTotalPrice).
                sum();
        */
    }

}

 

 

트랜잭션 스크립트 패턴 예시

public class SomeTransactionScript {
        public Result do(...) {
            try {
            
                SomeTransaction tx = ...;
                tx.begin();
                
                // 1. 잔고확인
                ...
                // 2. 받는 사람 확인
                ...
                // 3. 이체 실행
                ...
                // 4. 잔고 감소
                ...
                tx.commit();
                
            } catch(..) {
                tx.rollback();
                ...
            } finally {
                ...
                ...
            }
        }
    }

 

'개발일지 > 기타' 카테고리의 다른 글

XSS(Cross Site Script)란  (0) 2022.04.22