JavaScript中級

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

導入

ドメイン駆動設計(DDD)は、複雑なビジネス要件を扱う際に非常に有効なアプローチです。特に、業務ドメインの理解を深め、コードをそのドメインに沿って整理することで、メンテナンス性や拡張性を高めることができます。本記事では、具体的なシチュエーションとして「オンライン書店」を取り上げ、ドメイン駆動設計の実践的な側面を探ります。

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

重要な概念の整理

オンライン書店のシステムを考えると、主要なドメインは「書籍」「顧客」「注文」といったエンティティで構成されます。各エンティティは、それぞれのビジネスルールや振る舞いを持っており、これらを明確に分離することが重要です。さらに、ドメインイベントやリポジトリパターンを利用して、エンティティ間の関係を管理することが求められます。

コード例(JavaScript)


// 書籍エンティティ
class Book {
    constructor(title, author, price) {
        this.title = title;
        this.author = author;
        this.price = price;
    }

    applyDiscount(discountPercentage) {
        this.price -= this.price * (discountPercentage / 100);
    }
}

// 顧客エンティティ
class Customer {
    constructor(name) {
        this.name = name;
        this.orders = [];
    }

    placeOrder(book) {
        const order = new Order(this, book);
        this.orders.push(order);
        return order;
    }
}

// 注文エンティティ
class Order {
    constructor(customer, book) {
        this.customer = customer;
        this.book = book;
        this.date = new Date();
    }
}

// 使用例
const book = new Book('JavaScript: The Good Parts', 'Douglas Crockford', 3000);
book.applyDiscount(10);
const customer = new Customer('田中太郎');
const order = customer.placeOrder(book);
console.log(order);

コードの行ごとの解説

  1. 書籍エンティティを定義し、タイトル、著者、価格をプロパティとして持つ。
  2. 価格に対する割引を適用するメソッドを実装。
  3. 顧客エンティティを定義し、顧客名と注文履歴を管理。
  4. 顧客が書籍を注文する際のロジックを含むメソッドを実装。
  5. 注文エンティティを定義し、顧客情報と書籍情報、注文日を保持。
  6. 書籍と顧客を生成し、実際に注文を行う使用例を示す。

練習問題編

以下に、ドメイン駆動設計に関する練習問題を用意しました。各問題に対する模範解答と解説も記載しています。

  1. 問題1: 書籍エンティティに「在庫数」を追加し、在庫が不足している場合に注文を拒否するロジックを実装してください。
    模範解答:

    
    // 在庫数を追加
    class Book {
        constructor(title, author, price, stock) {
            this.title = title;
            this.author = author;
            this.price = price;
            this.stock = stock; // 在庫数
        }
    
        placeOrder(quantity) {
            if (this.stock < quantity) {
                throw new Error('在庫が不足しています');
            }
            this.stock -= quantity; // 在庫を減らす
        }
    }
    
  2. 問題2: 顧客が複数の書籍を同時に注文できるように、placeOrderメソッドを変更してください。
    模範解答:

    
    class Customer {
        placeOrder(books) {
            const orders = books.map(book => new Order(this, book));
            this.orders.push(...orders);
            return orders;
        }
    }
    
  3. 問題3: 注文エンティティに「合計金額」を計算するメソッドを追加してください。
    模範解答:

    
    class Order {
        calculateTotal() {
            return this.book.price; // 単一書籍の場合
        }
    }
    

まとめ

  • ドメイン駆動設計では、ビジネスのルールをコードに反映させることが求められる。
  • エンティティ間の関係や振る舞いを明確に定義することで、システムの理解が深まる。
  • 実際の業務においては、ビジネス要件の変化に柔軟に対応できる設計が重要である。