📘

【設計パターン入門】値オブジェクトと完全コンストラクタについての個人的まとめ

2022/11/13に公開

值物件:Value Object(値オブジェクト)
完全建構子:Complete Constructor(完全コンストラクタ)

参考資料:「良いコード・悪いコードで学ぶ設計入門」
参考記事
参考記事

値オブジェクトとは

  • 値をクラス(型)として表現する設計パターン」のこと
Money price; 
//ただのint としてではなく、Moneyクラス型の price として宣言する

なぜ値オブジェクトなのか

普段値を定義したりするときに「int」「String」などのプリミティブ型があるが、その中で同じint型でも「point」「age」「price」など同じ整数値でも意味が異なる値がある。これは業務上の意味を持っていることになる。
ただし、

  • クラスにはsetter/getterなどのメソッドを定義することがしばしばあり、int 型のまま宣言していると想定と違う値が格納される危険性がある

よって値の概念そのものを「クラス(型)」として表現し定義時に宣言すると、クラス型じゃない値を入れることができなくなる。よってクラスの安全性が増すことになる。

完全コンストラクタとは

  • インスタンス化を確実にできるように「未初期化」の対策や「不正値」の混入を防ぐコンストラクタのバリデーションを設置すること
public class Money {
  // フィールド変数割愛(private int priceとか private double taxRateとか)

    public Money(double taxRate) {
        if (tax < 0) throw new
                IllegalArgumentException("不正値:値が" + 0 + "未満です");
        if (taxRate > 1) throw new
                IllegalArgumentException("不正値:値が" + 1 + "以上です");
        this.taxRate = taxRate;
    }
    // コンストラクタ
    // ここでコンストラクタを設置して、確実に未初期化を防ぐ
    // さらにバリデーションを設置して不正値の混入を防ぐ

    //メソッドたち(private)は割愛
}

なぜ完全コンストラクタなのか

「未初期化」の対策や「不正値」の混入を防ぐコンストラクタのバリデーションを設置することで「インスタンスオブジェクトを作った瞬間から完全体にしておく」ことができる。
金額に負の数は無いように、int 型としては間違いじゃないものの、

  • 業務上明らかにおかしい値で初期化されたりそもそも未初期化で生焼けである状態を防いだりする目的がある。
  1. インスタンス変数を全て初期化できるだけの引数をもったコンストラクタを用意する
  2. コンストラクタでは不正値を弾くためのバリデートをかける。

値オブジェクトと完全コンストラクタ

  • 「意味」を持つ値をできるだけ値オブジェクトで「クラス型」の変数として宣言し、
  • 未初期化・不正値を防ぐバリデートを作ることで「完全コンストラクタ」とする

ことがオブジェクト指向の基本らしい

考察

値オブジェクトと完全コンストラクタを実現するための手順としては

  1. 関連するメンバを集めて高い凝縮度を保ったクラスを作る
  2. クラスに未初期化を防ぐコンストラクタと不正値を防ぐバリデートを忘れずに作る
  3. 扱う変数に意味がある場合はMoney money;といった具合に値オブジェクトにして、完全コンストラクタの「不正値混入の防止」につなげる。

がええんかと思ったりする。

まだまだ設計パターンについて入門者なのでお手柔らかに見ていただけると幸いです!

GitHubで編集を提案

Discussion