
ドメイン駆動設計(DDD: Domain Driven Design) における基本4パターンを解説したいと思います。
これらは、オブジェクト指向を「現実世界の概念モデル」に近づけるための設計指針なので、ちゃんと理解しておきたいパターンです。
4つのパターンをそれぞれ個別に解説してサンプルコードを掲載しておきます。
それらを組み合わせた関連性について把握して、デザインパターンを理解しましょう。
① Entity(エンティティ)
・識別子(ID)によって区別されるオブジェクト。
・属性が変わっても「同一のもの」として扱われる。
・永続化(DB保存)対象であり、ライフサイクルを持つ。
サンプルコード
class User {
constructor(id, name, email) {
this.id = id; // ← 同一性を保証
this.name = name;
this.email = email;
}
}
const u1 = new User(1, "Alice", "a@example.com");
const u2 = new User(1, "Alice", "b@example.com");
console.log(u1.id === u2.id); // true(同一エンティティ)
ポイント解説
・id が同じなら同一人物(状態が変化しても同じオブジェクト)。
・状態を更新できる(mutable)。
② Value Object(値オブジェクト)
・属性の集合であり、IDではなく値そのもので等価を判定する。
・不変(immutable)が原則。
・意味的な単位を明確化するために使う。
サンプルコード
class Money {
constructor(amount, currency) {
this.amount = amount;
this.currency = currency;
Object.freeze(this); // ← 不変にする
}
equals(other) {
return this.amount === other.amount && this.currency === other.currency;
}
}
const m1 = new Money(100, "JPY");
const m2 = new Money(100, "JPY");
console.log(m1.equals(m2)); // true(値が同じなら同一)
ポイント解説
・値が等しければ同じオブジェクトと見なす。
・計算結果として新しいインスタンスを返す(副作用なし)。
③ Aggregate(集約)
・関連するエンティティや値オブジェクトをひとまとめに扱う構造。
・整合性の単位(トランザクション境界) を定義する。
・集約の入り口は「集約ルート(Aggregate Root)」と呼ばれる。
サンプルコード
class OrderItem {
constructor(product, quantity, price) {
this.product = product;
this.quantity = quantity;
this.price = price;
}
getTotal() {
return this.quantity * this.price;
}
}
class Order { // Aggregate Root
constructor(id, customer) {
this.id = id;
this.customer = customer;
this.items = [];
}
addItem(product, quantity, price) {
this.items.push(new OrderItem(product, quantity, price));
}
getTotalAmount() {
return this.items.reduce((sum, i) => sum + i.getTotal(), 0);
}
}
ポイント解説
・Order が集約ルート。
・OrderItem は Order 経由でしか変更できない。
・データの整合性を保証。
④ Repository(リポジトリ)
・永続化の抽象化層。
・データストア(DB、API、キャッシュなど)の実装を隠す。
・アプリケーションは「コレクションのように」ドメインオブジェクトを操作できる。
サンプルコード
class OrderRepository {
constructor() {
this.orders = new Map();
}
save(order) {
this.orders.set(order.id, order);
}
findById(id) {
return this.orders.get(id);
}
findAll() {
return Array.from(this.orders.values());
}
}
ポイント解説
・ドメイン層からDBアクセスロジックを切り離す。
・永続化の方式(SQL / NoSQL)を後から変更しても影響が少ない。
関係性(DDDの構成)
[Entity]
│↑ unique identity(例: User,Order)
│
├ contains
│↑ [Value Object](例: Address,Money)
│
└ grouped into
│ ↑ [Aggregate](整合性の単位)
│
└ accessed through
↑ [Repository](永続化の抽象層)
注意点
EntityとValueObjectを混同すると、整合性管理が破綻しやすいので要注意です。
Aggregateを細かく分けすぎると、トランザクションが複雑になルので、これも設計に気をつける必要があります。
Repositoryはあくまでドメイン層のための抽象化(DAOとは違う)と言う扱いが良いようです。
あとがき
流行りのDDDですが、ドメイン駆動をちゃんと理解しておかないと、設計する時にミスに気がつかない場合もあります。
サンプルコードは、よくあるユーザーの課金オーダーの処理を簡単にコーディングした例ですが、
システム種別によって、さまざまなクラスが作られることがあります。
ただ、4つの工程を理解して、ドメイン駆動が理解して意識できるようになると、安定した設計につながるはずです。
改めて設計って重要!と感じた、デザインパターンの学習でしたね。
0 件のコメント:
コメントを投稿