ドメイン主導設計(7)-ドメインサービス


ドメインサービス


複数のagrigatの機能が必要です

  • ドメインコードを記述する場合、agrigate実装機能を1つ使用できない場合があります.
  • の代表的な例は、決済金額計算ロジックである.
  • 商品アグリグット:購入する必要がある商品の価格.また、商品によって配送料も加算されます.
  • アグリグットを注文:商品ごとに購入数が必要です.
  • 割引クーポンアグリグット:クーポンで指定された割引金額または割合で、注文総額を割引します.条件に応じて割引クーポンを繰り返し使用したり、指定したカテゴリの商品にのみ適用できる制約があれば、割引の計算は複雑になります.
  • 会員アグリグット:会員等級によって追加割引があります.
  • の実際の決済金額を計算する必要がある主体は?決済金額の計算ロジックは注文アグリガーの責任ですか?
  • の合計受注金額の計算は、受注アグリガーによって行うことができるが、
  • 総注文金額のうち、割引金額を計算する必要がある場合は?割引クーポンアグリグロトロは単一クーポンとしてもよいが、複数のクーポンに適用されると計算しにくい.
  • 特別割引ですべての商品に対して1ヶ月間の割引を実施する場合、注文agrigatの構成要素に関係なくても、決済金額の計算責任を負う場合は、注文agrigatのコードを修正する必要があります.
  • 特定のagrigatに
  • を入れるのに適さないドメイン機能を強制的に実装することはできない.
  • の場合、agrigatはその職責範囲を超えた機能を実現するため、コードが長くなり、外部への依存も増加する.
  • はコードを複雑にし、修正を困難にする.
  • アグリグットの範囲を超えるドメイン概念はアグリグットに隠され、明確に表示されない.
  • これらの問題を解決する最も簡単な方法は、ドメインサービスを単独で実施することである.

    ドメインサービスの個別実装

  • ドメインサービスを使用して、ドメイン概念を明示的に示すことができる.
  • アプリケーション領域のサービスがアプリケーションロジックに関連する場合、ドメインサービスはドメインロジックに関連する.
  • ドメインサービスは、aggregatまたはvalueなどのドメイン内の他のコンポーネントと比較して、異なる点がある場合、無状態の論理のみを実現する.
  • ドメインサービスを実現するために必要な状態はagrigatまたは他の方法によって伝達される.
  • ex)割引を計算するためのドメインサービス
    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(orderer.getMember().getGrade())return couponDiscount.add(membershipDiscount);
    
        }
    
        private Money calculateDiscount(Coupon coupon) {
            ...
        }
    
        private Money calculateDiscount(MemberGrade grade) {
            ...
        }
    
    }

  • 割引計算サービスを利用する主体はagrigatであってもよいし、アプリケーションサービスであってもよい.

  • DiscountCalculationServiceをAgrigatの決済金額計算機能に渡すと、使用主体はAgrigatになります.

  • ドメイン・サービスをアグリゲート・オブジェクトに渡すことは、アプリケーション・サービスの責任です.
    // 애그리거트의 결제 금액 계산 기능을 도메인 서비스가 처리
    public class Order {
    
        public void calculateAmounts(
            DiscountCalculationService disCalSvc, MemberGrade grade) {
            Money totalAmounts = getTotalAmounts();
            Money discountAmounts =
                disCalSvc.calculateDiscajrrtAnouits(this.orderLines, this.coupons, grade);
            this.paymentAmounts = totaBVnounts.minus(discountAmounts);
        }
        ...
    }
  • agridgetメソッドを実行すると、ドメインサービスをパラメータとして渡さず、逆にドメインサービス機能を実行するとagridgetも渡されます.
  • ex)振込機能
    public class TransferService {
        public void transfer(Account fromAcc, Account toAcc, Money amounts) {
            fromAcc.withdraw(amounts);
            toAcc.credit(amounts);
        }
        ...
    }
  • 振り込みの場合、2つの口座がアグリグットが参加します.
  • 漢アグリグット送金
  • ハンアグリグット送金.
  • アプリケーションサービスは、2つのAccount Agreegateを取得した後、ドメイン内のTransferServiceを使用して、カバー左折勘定ドメイン機能を実行します.
  • ドメインサービスはドメインロジックを実行するが、アプリケーションロジックは実行しない.
  • トランザクションのような論理はアプリケーションロジックであり、ドメインサービスではなくアプリケーションサービスによって処理されるべきである.
  • 特定の機能がアプリケーション・サービスなのかドメイン・サービスなのかを判断するのが難しい場合は、その論理がagrigatのステータスを変更したか、agrigatのステータス値を計算したかを確認できます.
  • 振り込みロジックアカウントアグリグットの状態を変更します.
  • 決済金額論理は、受注アグリグットの受注金額を計算する.
  • この2つの論理は、それぞれagrigatを変更し、agrigat値を計算するドメイン論理である.この2つのロジックは、ドメインロジックであり、agrigatに配置するのに適していないため、ドメインサービスとして実装されます.
  • 도메인 서비스 객체를 애그리거트에 주입하지 않기

  • agrigatメソッドを実行すると、ドメインサービスオブジェクトがパラメータとして渡され、これはagrigatがドメインサービスに依存することを意味する.
  • SpringのDIとAOPを学習すると、agrigatに依存するドメインサービスを処理するために依存注入を使用したい場合があります.関連技術に夢中になると、特にそうです.フレームワークが提供する依存注入機能を使用してドメインサービスをagrigatに注入してこそ、技術的に改善される.
  • ですが、本の著者から見れば、これは良い方法ではありません.△これは主観的な考え方であり、もちろん自動注入などに依存する開発者もいる.
  • 依存注入を行うために、ドメインサービスへの参照がフィールドとして追加される.
    public class Order {
    		@Autowired
    		private DiscountCalculationService discountCalculationService;
    }
  • ドメインオブジェクトは、フィールドからなるデータおよび使用方法の機能を使用して、モデルを概念的に表す.
  • モデルのデータを含むフィールドは、モデルの重要なコンポーネントです.
  • ただし、割引計算サービスフィールドは、データ自体とは無関係である.データベース・ストレージ・オブジェクトでもありません.さらに、Order Agreegerが提供するすべての機能には、DiscountCalculationServicefmfは必要ありません.
  • の一部の機能しか必要ありません.いくつかの機能のために、ドメインサービスオブジェクトをagrigatに注入する理由はありません.
  • 要約
  • は、ドメイン・サービス・オブジェクトがターゲットagrigatのすべての機能で使用されていない場合、paramを所望の方法に伝達するように実装され、メンテナンスが容易な方法である.
  • ドメインサービスのパッケージの場所

  • ドメインサービスはドメインロジックを実行するので、ドメインサービスの位置は他のドメインコンポーネントと同じパッケージにある.すなわち、ドメインサービスはドメイン領域に存在する.
  • ドメイン・サービスの数が多い場合、またはエンティティや価値などの他のコンポーネントと明確に区別したい場合は、ドメイン・パッケージの下部に分子パッケージを分割できます.
  • domain.model
  • domain.service
  • domain.repository
  • ドメイン・サービスのインタフェースとクラス


    固定された
  • ドメインサービスロジックがない場合、ドメインサービス自体をインタフェースとして実装し、実装されたクラスとして実装することができる.
  • 特に、外部システムまたは個別のエンジンを使用してドメインロジックを実装する必要がある場合、インタフェースとクラスは分離される.
  • ex)割引金額計算ロジックは、特定の技術に属する場合、インタフェースと実装クラスに分けられる.
  • ドメイン・サービスの実装が特定の実装技術に依存する場合、または外部システムのAPIを実行する場合、ドメイン・ドメイン内のドメイン・サービスはインタフェースとして抽象化されるべきである.
  • は、ドメインが特定の実施形態に依存することを防止するのに役立つ、
  • .
  • ドメインのテストがより容易になりました.(インタフェースとして検証するテスト実施)