[DDDStart] 7장. 도메인 서비스

7장. 도메인 서비스

도메인 서비스 ?

도메인 단위로 나눠서 개발을 하다 보면 비즈니스 기능을 구현하는데 여러 애그리거트가 필요한 경우가 생김

ex) 결제 금액 계산 로직

 

결제 금액을 계산할 때 결제 애그리거트 와 함께 하는 애그리거트 예

지불 금액 = 총 비용 - 쿠폰 할인 - 회원 추가 할인

 

Solution 1. 주문 애그리거트에 로직 넣기 ❌

주문 애그리거트에 상품, 할인 쿠폰, 회원 등을 넣고, 결제 금액을 계산하는 메서드를 만들면 구현할 수 있다.

 

Solution 2. 별도의 클래스 (도메인 서비스) 만들기 ✔️

자. 지금 도메인 서비스를 만들거다

응용 서비스는 응용 로직을 다루고, 도메인 서비스는 도메인 로직을 다룬다

다만, 도메인 서비스는 해당 로직이 여러 애그리거트를 필요로 할 때 사용되며, 상태가 없다는 것을 기억해야 함.

 

public class DiscountCalculationService {
    public Money calculateDiscountAmounts ( List<OrderLine> orderLines, List<Coupon> coupons, MemberGrade grade) {

            Money couponDiscount = coupons.stream()
                                    .map(coupon -> calculateDiscount(coupon))
                                    .reduce(Money(0), (v1, v2) -> v1.add(v2));

            Money membershipDiscount = calculateDiscount(grade);

            return couponDiscount.add(menbershipDiscount);
        }
    }   

    private Money calculateDiscount(Coupon coupon) { ... }
    private Money calculateDiscount(MemberGrade grade) { ... }

}

p206 오타같음. 위 코드는 오탈자 수정한 것

 

How to USE

자, 클래스 만들었다. 이거 어디서 필요한거야? 누가 필요해서 메시지를 전달한거야?

특정 기능이 응용 서비스인지, 도메인 서비스인지 헷갈려요~

-> 해당 기능이 도메인 로직 (애그리거트를 변경하거나 값을 계산하는 로직) 이면서 한 애그리거트에 넣기 적합하지 않은 경우는 도메인 서비스다.

-> 결국 도메인 서비스에는 도메인 로직이 온다는 말임. 응용서비스에는 도메인 로직이 없음

 

TODOTODO :: 루트 애그리거트는 도메인 서비스를 몰라도된다!! 에 대해서 고민

주의) 도메인 서비스 클래스를 DI 하지 않기

DI 한다는 것은 객체를 ApplicationContext에 등록시키는 것이다. 사용하고 싶을 때는 필드로 만들고, 주입받아서 쓴다.

하지만 루트 애그리거트에서 위처럼 주입받아서 쓰면 ..

DiscountCalculationService 필드는 DB로 저장하는 필드가 아님. 또한 모든 메서드에서 DiscountCalculationService 필드를 필요로 하진 않음

 

패키지 위치

도메인 서비스가 외부 시스템에 의존한다면 ?

도메인 서비스의 로직이 고정되어 있지 않고 여러개일 경우에는 인터페이스로 추상화시키고 구현체를 여러개 만들면 됨

 

Q1. Order에서 DI 해서 쓰지 말고 그럼… 서비스단에서 받아서 쓰나..? 자기가 new 해서 쓰나..?

서비스단에서 주입받아서 쓴다. 도메인 서비스는 상태를 가지지 않으므로 서비스에서 상태도 파라미터로 함께 제공 해주어야 함

 

Q2. DiscountCalculationService를 왜 OrderService에서 쓰는게 아니라 왜 Order가 호출하지? p207

..