TypeScript中級

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

導入

ドメイン駆動設計(DDD)は、複雑なビジネスロジックを効果的に管理するための強力な手法です。特に、TypeScriptを用いることで、型安全性を活かしながら、より明確な設計が可能になります。本記事では、実際のプロジェクトで遭遇しやすい「顧客管理システム」に焦点を当て、ドメイン駆動設計の実践的なアプローチを解説します。

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

重要な概念の整理

ドメイン駆動設計の中心には「ユビキタス言語」があります。これは、開発者とビジネス関係者が共通に使用する言語で、ドメインのモデルを明確に表現するためのものです。顧客管理システムの例では、顧客、契約、請求書などのエンティティが重要な要素となります。

また、集約(Aggregate)は、関連するエンティティを一つの単位として扱うための概念です。集約を適切に設計することで、データの整合性を保ちながら、システムの複雑さを軽減できます。

コード例(TypeScript)


class Customer {
    private _id: string;
    private _name: string;
    private _contracts: Contract[];

    constructor(id: string, name: string) {
        this._id = id;
        this._name = name;
        this._contracts = [];
    }

    public addContract(contract: Contract): void {
        this._contracts.push(contract);
    }

    public getContracts(): Contract[] {
        return this._contracts;
    }
}

class Contract {
    private _contractId: string;
    private _amount: number;

    constructor(contractId: string, amount: number) {
        this._contractId = contractId;
        this._amount = amount;
    }
}

コードの行ごとの解説

  1. class Customer { – 顧客を表すクラスの定義。
  2. private _id: string; – 顧客のIDを保持するプライベートプロパティ。
  3. private _name: string; – 顧客の名前を保持するプライベートプロパティ。
  4. private _contracts: Contract[]; – 顧客が持つ契約の配列。
  5. constructor(id: string, name: string) { – コンストラクタでIDと名前を初期化。
  6. public addContract(contract: Contract): void { – 契約を追加するメソッド。
  7. return this._contracts; – 顧客の契約を取得するメソッド。
  8. class Contract { – 契約を表すクラスの定義。
  9. private _contractId: string; – 契約IDを保持するプライベートプロパティ。
  10. private _amount: number; – 契約金額を保持するプライベートプロパティ。

練習問題編

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

  1. 問題1: 顧客クラスに、契約の合計金額を計算するメソッドを追加してください。
  2. 問題2: 顧客が持つ契約をIDで検索するメソッドを実装してください。
  3. 問題3: 顧客クラスに、契約を削除するメソッドを追加し、契約が存在しない場合はエラーメッセージを表示するようにしてください。

模範解答と解説

問題1: 合計金額を計算するメソッドを追加することで、顧客が持つ契約の全体像を把握しやすくなります。


public calculateTotalAmount(): number {
    return this._contracts.reduce((total, contract) => total + contract.amount, 0);
}

問題2: 契約をIDで検索することで、特定の契約の情報を迅速に取得できます。


public findContractById(contractId: string): Contract | undefined {
    return this._contracts.find(contract => contract.contractId === contractId);
}

問題3: 契約を削除することで、顧客の契約情報を最新の状態に保つことができます。


public removeContract(contractId: string): void {
    const index = this._contracts.findIndex(contract => contract.contractId === contractId);
    if (index !== -1) {
        this._contracts.splice(index, 1);
    } else {
        console.error('契約が見つかりません。');
    }
}

まとめ

  • ドメイン駆動設計は、ビジネスロジックを効果的に管理するための手法である。
  • ユビキタス言語と集約の概念を理解することで、設計の質を向上させる。
  • TypeScriptを活用することで、型安全性を持った設計が可能になる。