TypeScript上級

上級 TypeScriptで学ぶドメイン駆動設計|練習問題編

導入

ドメイン駆動設計(DDD)は、複雑なビジネスロジックを扱う際に非常に効果的なアプローチです。特に、実務においては、ドメインの理解がシステム全体の設計に大きな影響を与えます。今回は、TypeScriptを用いて、現場でよく遭遇する「注文管理システム」を題材に、ドメイン駆動設計の実践的な適用方法を考えていきます。

教科書レベルの解説(ドメイン駆動設計)

重要な概念の整理

ドメイン駆動設計では、ドメインモデルを中心にシステムを構築します。具体的には、エンティティ、値オブジェクト、集約、リポジトリなどの概念を用いて、ビジネスルールを明確にし、システム全体の整合性を保つことが求められます。特に注文管理システムでは、注文の状態遷移や、注文に関連するビジネスロジックが重要なポイントとなります。

コード例(TypeScript)


class Order {
    private items: OrderItem[] = [];
    private status: OrderStatus;

    constructor(private id: string) {
        this.status = OrderStatus.CREATED;
    }

    public addItem(item: OrderItem): void {
        if (this.status !== OrderStatus.CREATED) {
            throw new Error("Cannot add items to an order that is not in the CREATED status.");
        }
        this.items.push(item);
    }

    public checkout(): void {
        if (this.items.length === 0) {
            throw new Error("Cannot checkout an empty order.");
        }
        this.status = OrderStatus.COMPLETED;
    }

    public getStatus(): OrderStatus {
        return this.status;
    }
}

enum OrderStatus {
    CREATED,
    COMPLETED,
}

class OrderItem {
    constructor(public productId: string, public quantity: number) {}
}

コードの行ごとの解説

  1. class Order { – 注文を表すクラスの定義。
  2. private items: OrderItem[] = []; – 注文に含まれるアイテムを保持する配列。
  3. private status: OrderStatus; – 注文の状態を管理するプロパティ。
  4. constructor(private id: string) { – 注文のIDを初期化するコンストラクタ。
  5. this.status = OrderStatus.CREATED; – 注文作成時の初期状態を設定。
  6. public addItem(item: OrderItem): void { – 注文にアイテムを追加するメソッド。
  7. if (this.status !== OrderStatus.CREATED) { – 注文の状態をチェックし、アイテム追加の可否を判断。
  8. public checkout(): void { – 注文を完了するメソッド。
  9. if (this.items.length === 0) { – 注文が空でないかを確認。
  10. public getStatus(): OrderStatus { – 現在の注文状態を取得するメソッド。

練習問題編

以下の練習問題に取り組んでみてください。

  1. 問題1: 注文にアイテムを追加する際、アイテムの数量が0以下の場合はどうなるか、エラーハンドリングを追加してください。

    
    public addItem(item: OrderItem): void {
        if (item.quantity <= 0) {
            throw new Error("Item quantity must be greater than zero.");
        }
        // 既存のロジック
    }
    
  2. 問題2: 注文の状態を「キャンセル」に変更するメソッドを追加してください。

    
    public cancel(): void {
        if (this.status === OrderStatus.COMPLETED) {
            throw new Error("Cannot cancel a completed order.");
        }
        this.status = OrderStatus.CANCELLED;
    }
    
  3. 問題3: 注文のアイテムを取得するメソッドを実装してください。

    
    public getItems(): OrderItem[] {
        return this.items;
    }
    

まとめ

  • ドメイン駆動設計は、ビジネスロジックの明確化に寄与する。
  • エンティティと値オブジェクトの役割を理解し、適切に利用することが重要。
  • 実際の業務においては、エラーハンドリングや状態管理が鍵となる。