1️⃣

[読書メモ]オブジェクト設計スタイルガイド 8章1節 with TypeScript

2024/03/12に公開

オブジェクト設計スタイルガイドを読みながら、TypeScriptでやるならどうやるかを考えながら書きました。
要約的に読める内容になっていると思うので、サクッと3分ぐらいで読める記事となっています。
https://www.oreilly.co.jp/books/9784814400331/

8 責務の分割

8.1 リードモデルとライトモデルを分ける

リファクタ前の例

class PurchaseOrder {
  private _purchaseOrderId: number;
  private _productId: number;
  private _quantity: number;
  private _wasReceived: boolean;

  private constructor() {}

  // ① 簡略化のためプリミティブ型を使っているが、実際はValueObjectを使う
  static place(purchaseOrderId: number, productId: number, quantity: number) {
    const order = new PurchaseOrder();
    order._purchaseOrderId = purchaseOrderId;
    order._productId = productId;
    order._quantity = quantity;
    order._wasReceived = false;
    return order;
  }

  markAsReceived() {
    this._wasReceived = true;
  }

  get purchaseOrderId() {
    return this._purchaseOrderId;
  }

  get productId() {
    return this._productId;
  }

  get quantity() {
    return this._quantity;
  }

  get wasReceived() {
    return this._wasReceived;
  }
}

更新時の使用例: この処理では書き込みのみに関心がある

class ReceiveItems {
  private repository: repository;

  constructor(repository: repository) {
    this.repository = repository;
  }

  receiveItems(purchaseOrderId: number) {
    const order = this.repository.find(purchaseOrderId);
    order.markAsReceived();
    this.repository.save(order);
  }
}

取得時の使用例: この処理では読み込みのみに関心がある

class StockReportController {
  private repository: repository;

  constructor(repository: repository) {
    this.repository = repository;
  }

  execute(request: any) {
    const allOrders = this.repository.findAll();
    const stockReport = {}:

    allOrders.forEach((order: any) => {
      if (!order.wasReceived) {
        continue;
      }
      if (!stockReport[order.productId]) {
        stockReport[order.productId] = 0;
      }
      stockReport[order.productId] += order.quantity;
    });

    return new JsonResponse(stockReport);
  }
}

リファクタ: リードモデルとライトモデルを分ける

class PurchaseOrderForStockReport {
  private _productId: number;
  private _quantity: number;
  private _wasReceived: boolean;

  constructor(productId: number, quantity: number, wasReceived: boolean) {
    this._productId = productId;
    this._quantity = quantity;
    this._wasReceived = wasReceived;
  }

  get productId() {
    return this._productId;
  }

  get quantity() {
    return this._quantity;
  }

  get wasReceived() {
    return this._wasReceived;
  }
}

class PurchaseOrder {
  private _purchaseOrderId: number;
  private _productId: number;
  private _quantity: number;
  private _wasReceived: boolean;

  private constructor() {}

  static place(purchaseOrderId: number, productId: number, quantity: number) {
    const order = new PurchaseOrder();
    order._purchaseOrderId = purchaseOrderId;
    order._productId = productId;
    order._quantity = quantity;
    order._wasReceived = false;
    return order;
  }

  markAsReceived() {
    this._wasReceived = true;
  }
}

Discussion