新しいプロジェクトの場合は、非常にエレガントなこの階層構造を採用するとよいでしょう。

皆さんこんにちは、ピャオ・ミャオです。今日も DDD とマイクロサービスに関する一連の記事を更新し続けます。

コラムの冒頭で述べたように、DDD (Domain-Driven Design、ドメイン駆動設計) は学ぶのがより複雑で、多くの概念が含まれる一方で、実践的な経験や経験が不足していることがよくあります。明確なコードモデルのガイダンス。今日は、DDD の階層化アーキテクチャとエンティティ モデルに焦点を当て、DDD を実装するすべての人に役立つ参考資料を提供したいと考えています。まず、おなじみの MVC 3 層アーキテクチャを確認してみましょう。

1.MVCアーキテクチャ

従来のアプリケーションでは、通常、システム全体を Model (モデル)、View (ビュー)、Controller (コントローラー) の 3 つのレベルに分割する古典的な MVC (Model-View-Controller) アーキテクチャを開発に使用する標準的なソフトウェアです。ユーザービューをビジネス処理から分離し、コントローラーを介してそれらを接続して、プレゼンテーションとロジックの適切な分離を実現するレイヤードアーキテクチャ。

この層状アーキテクチャに従った開発プロセスでは、通常、次の図に示すように、プレゼンテーション層、ロジック層、データ アクセス層に対応するコントローラー、サービス、Dao の 3 つの Maven モジュールを作成します。

(モデルは通常、データベース テーブルに対応する属性のみを含む単なる単純な Java Bean であるため、図には追加のモデル レイヤーが描かれています。一部のアプリケーションはこれを Maven モジュールとして個別に抽出しますが、実際にはマージできます。 DAO 層に追加します。)

1.1 MVC アーキテクチャ モデルの欠陥

比較的単純なビジネス ロジックを備えたアプリケーションでは、MVC 3 層アーキテクチャはシンプルで効率的な開発モデルです。ただし、ビジネス ロジックが複雑になり、コードの量が増えると、MVC アーキテクチャが拡張される可能性があります。その主な欠点は次のように要約できます。

  • サービス層の責任が多すぎる: M​​VC アーキテクチャでは、サービス層には複雑なビジネス ロジックを処理するタスクが与えられることがよくあります。ビジネス ロジックが成長するにつれて、サービス層が肥大化して複雑になる可能性があります。ビジネス ロジックはさまざまなサービス クラスに分散している場合があり、ビジネス ロジックの編成と保守が困難になります。
  • データベースに注目しすぎてドメイン モデリングが無視される: M​​VC の本来の目的はデータ、ユーザー インターフェイス、制御ロジックを分離することですが、複雑なビジネス シナリオに直面してドメイン モデリングには十分な注意が払われません。コードはビジネス要件よりもデータベースを中心に設計されているため、コードの理解や拡張が困難になる可能性があります。
  • 不明確な境界分割: MVC アーキテクチャでは、トップレベル設計の境界分割に関する明確なルールはなく、多くの場合、技術リーダーの経験に依存します。大規模なチームでのコラボレーションでは、責任の所在や役割の分担が不明確になるなどの問題が発生する可能性があります。
  • 単体テストは難しい: MVC アーキテクチャでは、サービス層は通常、トランザクション スクリプトの形式で開発され、多くの場合、データベース、キャッシュ、メッセージ キューなどのさまざまなミドルウェア操作と結合されます。これらのミドルウェアなしでテストを実行するには、大量のモック コードやスタブ コードが必要になる可能性があるため、この結合により単体テストが困難になります。

MVC アーキテクチャを詳しく調べた後、今日のトピックである DDD の階層化アーキテクチャ モデルに入ります。

2. DDDのアーキテクチャモデル

DDD では、アプリケーション プログラムは通常、ユーザー インターフェイス層 (インターフェイス層)アプリケーション層 (アプリケーション層)ドメイン層 (ドメイン層)インフラストラクチャ層 (インフラストラクチャ層)の 4 つのレベルに分かれており、各層はそれぞれの役割を果たします。責任と役割。階層モデルを次の図に示します。

  1. インターフェイス層 (インターフェイス層) : UI、Web API、RPC インターフェイスなどの外部システムとの対話の処理を担当します。ユーザーや外部システムからリクエストを受け取り、アプリケーション層のサービスを呼び出してリクエストを処理し、最終的に処理結果をユーザーや外部システムに返します。
  2. アプリケーション層(アプリケーション層):ドメイン層とインフラ層の調整を担い、具体的なビジネスロジックを実現します。ドメイン層のドメインサービスとインフラストラクチャ層の基本サービスを呼び出して、ビジネスロジックの実現を完了します。
  3. ドメイン層 (ドメイン層) : この層には、エンティティ、値オブジェクト、ドメイン サービス、集約、ファクトリ、ドメイン イベントなど、ビジネス ドメインのすべての要素が含まれています。この層の主な役割は、ビジネス ドメインのコア ロジックを実装することです。
  4. インフラストラクチャ層: 主に、データの永続化、キャッシュ、メッセージ送信などのインフラストラクチャ サービスなどの一般的な技術機能を提供します。他の 3 つのレイヤーから呼び出して、必要なさまざまな技術サービスを提供できます。

これら 4 つの層では、通常、呼び出し関係は一方向に依存します。つまり、上位層は下位層に依存し、下位層は上位層に依存しません。たとえば、インターフェイス層はアプリケーション層に依存し、アプリケーション層はドメイン層に依存し、ドメイン層はインフラストラクチャ層に依存します。ただし、インフラストラクチャ層は物理構造の最下位に位置する場合がありますが、DDD の階層モデルでは最外層に位置し、内部層に技術サービスを提供することに注意してください

2.1 依存関係逆転の原理

依存性反転原則 (DIP) は、モジュール間の結合を減らし、システムの拡張性と保守性を向上させるのに役立つ効果的な設計原則です。依存関係逆転の原則の中心的な考え方は、高レベルのモジュールは低レベルのモジュールに直接依存すべきではなく、すべて抽象化に依存すべきであるということです。抽象化は具体的な実装に依存すべきではなく、具体的な実装は抽象化に依存する必要があります。

DDD の 4 層アーキテクチャでは、ドメイン層がコアであり、ビジネスの抽象化であり、他の層に直接依存すべきではありませんこれは、ドメイン層のビジネス オブジェクトが、特定のデータベース アクセス テクノロジーやメッセージ キュー テクノロジーなどに直接依存するのではなく、他の層 (インフラストラクチャ層など) から分離される必要があることを意味します。ただし、実際の運用では、ドメイン層のオブジェクトは、インフラストラクチャ層を介したデータの永続化とメッセージ送信を実装する必要があります。

この問題を解決するには、依存関係逆転の原則を使用します。ドメイン層では、ドメイン オブジェクトに必要なサービスを宣言するためにいくつかのインターフェイス (ストレージ インターフェイスなど) を定義し、特定の実装はインフラストラクチャ層によって完了します。インフラストラクチャ層では、これらのインターフェイスを実装し、実装クラスをドメイン層のオブジェクトに注入します。このようにして、ドメイン層のオブジェクトは、インフラストラクチャ層に直接依存せずに、これらのインターフェイスを通じてインフラストラクチャ層と対話できます。

2.2 DDD 4 層アーキテクチャの利点

複雑なビジネス シナリオでは、DDD の 4 層アーキテクチャ モデルは、MVC アーキテクチャの使用時に発生する可能性のある問題を効果的に解決できます。

  1. 職務の分離: DDD の設計では、ビジネス ロジックをエンティティ、値オブジェクト、ドメイン サービスなどのドメイン オブジェクトにカプセル化しようとします。これにより、アプリケーション層 (元の MVC のサービス層) の複雑さが軽減され、同時にビジネス ロジックがより集中化され、明確になり、保守と拡張が容易になります。
  2. ドメイン モデリング: DDD の中心的な考え方は、含意のあるドメイン モデルを確立することでビジネス要件とビジネス ルールをより正確に反映し、それによってコードの柔軟性が向上し、ビジネスの変化への適応が容易になることです。
  3. 明確な境界分割: DDD は、境界付きコンテキスト (Bounded Context) の概念を使用して、システムの境界を明確に分割します。境界のある各コンテキストには独自のドメイン モデルとビジネス ロジックがあり、大規模なチーム コラボレーションがより明確かつ効率的になります。
  4. テストの容易さ: ビジネス ロジックはドメイン オブジェクトにカプセル化されているため、これらのドメイン オブジェクトを直接単体テストできます。同時に、インフラストラクチャ層(データベース、キャッシュ、メッセージキューなど)がインターフェイスとして抽象化され、テストにモックオブジェクト(Mock Object)を使用できるため、実際のミドルウェアとの直接のやり取りが回避され、柔軟性が大幅に向上します。テストの利便性、性別。

次に、コード内で DDD の階層化アーキテクチャに従う方法を見てみましょう。

3. DDD 階層化アーキテクチャの実装方法

DDD の階層構造に従うために、コード実装には 2 つの実装方法があります。

1 つ目は、モジュール内のパッケージごとに分離することです。つまり、ドメイン層 (ドメイン層)、アプリケーション層 (アプリケーション層)、インフラストラクチャ層 (インフラストラクチャ層)、およびユーザー インターフェイスに対応する 4 つの異なるコード パッケージをモジュール内に作成します。レイヤー (ユーザー インターフェイス レイヤー)。このアプローチの利点は、構造がシンプルで、理解と保守が簡単であることです。ただし、レイヤー間の依存関係が十分に明確でない可能性があり、コードの結合が容易に発生する可能性があるという欠点があります。

2 番目の実装方法は、4 つの異なる Maven モジュール層を確立することであり、各モジュールはドメイン層、アプリケーション層、インフラストラクチャ層、ユーザー インターフェイス層に対応します。この方法の利点は、層間の依存関係がより明確になり、結合が減少し、コードの再利用性が向上することです。同時に、このアプローチは、チーム メンバーが DDD の階層化されたアーキテクチャをよりよく理解し、従うのにも役立ちます。ただし、このアプローチではプロジェクト構造が複雑になり、プロジェクトのメンテナンスコストが増加する可能性があります。

実際のプロジェクトでは、プロジェクトの規模、チームメンバーの慣れ、プロジェクトの要件に応じて、適切な実装方法を選択できます。小規模なプロジェクトの場合は、最初の方法であるパッケージによる分離を使用できます。大規模なプロジェクトの場合は、コードの管理と保守を改善するために、Maven モジュール層を使用して分離する 2 番目の方法を採用することをお勧めします。どのようなアプローチであっても、重要なのは、DDD の原則とベスト プラクティスに従い、レイヤー間の責任を明確にすることです。

DailyMart プロジェクトでは、当初は最初の方法であるパッケージごとの分離を使用する予定でした。しかし、WeChat グループでのアンケートの結果、90% 近くの人が 2 番目の方法を選択したことが判明しました。ファンの意見に耳を傾けるブロガーとして、私は皆さんのアドバイスを受け入れることにしました。したがって、DailyMart はコーディングの練習に Maven モジュール層分離手法を使用します。

4. DDD のデータモデル

DDD では、特定のモデルを使用して、さまざまなドメインの概念と責任をマッピングおよび処理します。エンティティ オブジェクト (Entity)、データ オブジェクト (データ オブジェクト、DO)、およびデータ転送オブジェクト (データ転送オブジェクト、DTO) の 3 つの共通データ モデルがあります。これらのモデルには、DDD における明確な役割と使用シナリオがあります。

  • エンティティ (エンティティ オブジェクト):エンティティ オブジェクトはビジネス ドメインの中核概念を表し、そのフィールドとメソッドは、永続化メソッドに関係なく、ビジネス言語と一致している必要があります。これは、エンティティとデータ オブジェクトがまったく異なるフィールド名、フィールド タイプ、さらにはネストされた関係を持つ可能性があることを意味します。エンティティの存続期間はメモリ内にのみ存在する必要があり、シリアル化や永続化はできません。
  • データ オブジェクト (DO、データ オブジェクト): DO は、私たちの日常業務で最も一般的なデータ モデルかもしれません。DDD 仕様では、データ オブジェクトにビジネス ロジックを含めることはできず、インフラストラクチャ層に配置され、データベースとの対話のみを担当し、通常はデータベースの物理テーブルに対応します。
  • DTO (データ転送オブジェクト):データ転送オブジェクトは主に、コマンド (Command)、クエリ (Query)、イベント (Event)、リクエスト (Request) および応答 (応答)。DTO の重要性は、ビジネス オブジェクトが大きく複雑な「汎用」オブジェクトになるのを防ぐために、さまざまなビジネス シナリオで必要なパラメーターに適応できることです。

DDD では、次のような多くのシナリオで、これら 3 つのデータ オブジェクトを相互に変換する必要があります。

  1. エンティティ <-> DTO : アプリケーション層がデータを返すときは、エンティティ オブジェクトを DTO に変換する必要があります。これは通常、DTO Assemblerという名前のコンバータを通じて行われます。

  2. エンティティ <-> DO : インフラストラクチャ層でリポジトリを実装する場合、エンティティを DO に変換してデータベースに保存する必要があります。同様に、データをクエリするときは、DO をエンティティに変換し直す必要があります。これは通常、Data Converterと呼ばれるコンバータを使用して行われます。

もちろん、エンティティから DTO への場合でも、エンティティから DO への場合でも、コードの量や実行時の操作など、ある程度のオーバーヘッドが発生します。手書きの変換コードはエラーが発生しやすく、リフレクション テクノロジを使用するとコードの量は削減できますが、パフォーマンスが大幅に低下する可能性があります。ここでは、 Java を使用する学生にMapStructライブラリをお勧めします。MapStruct はコンパイル時にコードを生成し、対応するコードはインターフェイス定義とアノテーション構成を通じてのみ生成できます。生成されたコードが直接割り当てられるため、パフォーマンスの低下は無視できます。

SpringBoot ベテラン シリーズでは、少量のコードを記述するだけで済むため、オブジェクト変換には Orika を使用することをお勧めします。しかし、DDDではオブジェクトごとに厳密なコードレベルが設定されており、特殊なアセンブラやコンバータが導入されるのが一般的であり、コード量を節約できないため、最もパフォーマンスの高いコンポーネントを選択する必要があります。

さまざまなコンバーターのパフォーマンス比較: Java マッピング フレームワークのパフォーマンス | Baeldung

5. まとめ

この記事では、DDD の階層化アーキテクチャを詳しく紹介し、この階層化アーキテクチャをプロジェクト コードに実装する方法について詳しく説明します。同時に、DDD で一般的に使用される 3 つのデータ オブジェクト、データ オブジェクト (DO)、エンティティ (Entity)、およびデータ転送オブジェクト (DTO) について詳しく説明します。これら 3 つのデータ オブジェクトの違いは、次の図で詳細に説明し、要約することができます。

これまで、DDD の中核となる概念を詳しく分析してきました。同時に、DailyMart モール システムはすべての事前準備を完了し、実際のコーディング段階に入る準備が整いました。次の章では、登録プロセスの実装から始めて、実際のプロジェクトで DDD を適用する方法を段階的に検討していきます。

おすすめ

転載: blog.csdn.net/m0_60961651/article/details/131450317