この記事は、保守性の高いコード設計シリーズの続編です。前回までの記事では、メソッドや変数の整理方法を解説しました。今回は、オブジェクト指向設計の核となる「クラス」に焦点を当て、バグを未然に防ぐための堅牢な設計手法を探求します。
こんにちは。優れたクラス設計とは何でしょうか?それは、**「クラス単体で、正常に動作すること」**を目指すことに他なりません。
クラスは、システムの信頼性を支える重要な「部品」です。その部品が、外部からの予期せぬ使われ方によって簡単に壊れたり、不正な状態に陥ったりしてはなりません。すべてのクラスは、自身の状態を正常に保つ**「自己防衛責務」**を持っているのです。
今回は、その責務を果たすための第一歩として、オブジェクトが「生まれる」瞬間、すなわちコンストラクタの設計に焦点を当てます。
なぜ、自己防衛が必要なのか?
例えば、倉庫の在庫数を管理するInventory
というクラスを考えてみましょう。在庫数は、決してマイナスになってはいけません。しかし、以下のような単純なクラスではどうでしょうか。
【Before】無防備で、不正な状態になりえてしまうクラス
class Inventory {
String productCode;
int quantity;
}
このクラスは、誰でも簡単に不正な状態を作り出せてしまいます。
Inventory invalidStock = new Inventory();
invalidStock.productCode = null; // 商品コードがnull
invalidStock.quantity = -100; // 在庫数がマイナス
このような「不正なオブジェクト」の存在は、システムの至る所で予期せぬバグやエラーを引き起こす時限爆弾となります。
解決策:コンストラクタで正常値を保証する
この問題を解決するのが、「完全コンストラクタ (Complete Constructor)」 という設計パターンです。これは、オブジェクトの生成に必要なすべての情報をコンストラクタの引数で受け取り、内部でバリデーション(妥当性検証)を行うことで、不正な状態のインスタンスが作られることを100%防ぐ手法です。
【After】完全コンストラクタで武装した、頑強なクラス
class Inventory {
final String productCode;
final int quantity;
// コンストラクタで、正常な値だけを受け付ける
Inventory(final String productCode, final int quantity) {
// --- ガード節によるバリデーション ---
if (productCode == null) {
throw new NullPointerException("商品コードは必須です。");
}
if (quantity < 0) {
throw new IllegalArgumentException("在庫数には0以上を指定してください。");
}
// --- バリデーションここまで ---
this.productCode = productCode;
this.quantity = quantity;
}
}
このように、メソッドの先頭で不正な値をチェックし、問題があれば即座に例外を投げて処理を中断する手法をガード節と呼びます。
この設計により、Inventory
クラスのインスタンスは、生成された時点で必ず「商品コードを持ち、在庫数が0以上である」という正常な状態であることが保証されます。
// これはOK
Inventory validStock = new Inventory("A-123", 50);
// これはコンストラクタで例外が発生し、不正なインスタンスは作られない
// Inventory invalidStock = new Inventory("B-456", -10); -> IllegalArgumentException
まとめ
クラス設計とは、**「インスタンスをいかにして不正な状態から守るか」**という仕組み作りの側面が非常に強いです。
その最も基本的かつ強力な第一歩が、完全コンストラクタです。コンストラクタの責務は、単にフィールドを初期化することだけではありません。バリデーションを通じて、オブジェクトの「正常性」を生涯にわたって保証するという重要な役割を担っているのです。
さて、これで不正な状態のオブジェクトが生まれることはなくなりました。しかし、オブジェクトが使われている間に状態が変更され、不正な値になってしまったらどうでしょう?
▼次の記事 次回は、一度生成したオブジェクトの状態を変化させずに安全な操作を実現する不変性(Immutability)の概念と、それを体現した値オブジェクトという設計パターンについて詳しく解説します。