🏭

名前付きコンストラクタを使おう

2023/12/19に公開

概要

こんにちは。今年新卒で入社した株式会社ユーザベースでSaaSプロダクトのソフトウェアエンジニアをしているタイソンです。
今回は業務と自己学習で学んだオブジェクト設計のTipsを書いていこう思います。
そのTipsはエンティティ、valueオブジェクトなどを作成する際は名前付きコンストラクタを使おうというものです。

名前付きコンストラクタとは

名前付きコンストラクタはそのクラスのインスタンスを返すpublic staticなメソッドのことです。

class Student {
  private schoolName: string;
  private name: string;

  private constructor(schoolName: string, name: string) {
    this.schoolName = schoolName;
    this.name = name;
  }

  // 名前付きコンストラクタ
  static enroll(schoolName: string, name: string) {
    return new Student(schoolName, name);
  }
}

これには2つの利点があると考えます。

利点①

名前付きコンストラクトを利用することによって得られる利点にはオブジェクトの生成手段を複数提供できる点です。また注意点としては名前付きコンストラクタを使う場合は、オブジェクトが不正な状態で作成されてしまわないように通常のコンストラクタはprivateにしておくべきです。

class Money{
  readonly amount: number;
  private constructor(amount: number) {
    this.validateAmount(amount);
    this.amount = amount;
  }

  static fromNumber(amount: number) {
    return new Money(amount);
  }

  static fromString(amount: string) {
    const numberAmount = parseFloat(amount);
    if (isNaN(numberAmount)) {
      throw new Error("有効な数値の文字列である必要があります");
    }
    return new Money(numberAmount);
  }

  private validateAmount(amount: number): void {
    if (amount < 0) {
      throw new Error("金額は0以上である必要があります");
    }
  }
}

利点②

2つ目の利点としてはオブジェクトを作成する際にドメイン固有の言葉を使うことができる点です。
例えば新聞紙を表現した「Newspaper」クラスがあるとします。「Newspaper」はconstoructされるというよりかは、「発行(publish)」されるものでしょう。ドメイン固有の言葉を使うことによってドメインの意図をより正確に反映することができます。

class Newspaper {
  readonly title: string;
  readonly content: string;

  private constructor(title: string, content: string) {
    this.title = title;
    this.content = content;
  }

  public static publish(title: string, content: string) {
    return new Newspaper(title, content);
  }
}

まとめ

以上の利点を踏まえエンティティやvalueオブジェクトを作成する際には積極的に名前付きコンストラクタを使っていくのがいいと思います。

参考文献

  • Matthias Noback(2023)『オブジェクト設計スタイルガイド』(田中 祐一 訳)

Discussion