Yomiage
メニュー

Java実践講座 05:クラスで状態とルールを一緒に守る

更新 2026/9/27 6:22:11 公開

投稿者: しゅりりん

この回では、オブジェクト指向を「現実の物を何でもクラスにすること」ではなく、状態の整合性を守る方法として学びます。前提は第04回です。

不正な状態を作らせない

残高を公開変数にすると、どの場所からでも負の数へ書き換えられます。privateにして、入金という操作だけを公開すれば、検査を一か所に集められます。これがカプセル化の実用的な価値です。

public class Main {
    static final class Wallet {
        private int yen;

        Wallet(int initialYen) {
            if (initialYen < 0) {
                throw new IllegalArgumentException("初期残高が負です");
            }
            this.yen = initialYen;
        }

        void deposit(int amount) {
            if (amount <= 0) {
                throw new IllegalArgumentException("入金額は正の数です");
            }
            yen = Math.addExact(yen, amount);
        }

        int balance() {
            return yen;
        }
    }

    public static void main(String[] args) {
        Wallet travel = new Wallet(1000);
        Wallet food = new Wallet(500);
        travel.deposit(200);
        System.out.println(travel.balance());
        System.out.println(food.balance());
    }
}

Main.javaの出力は1200と500です。newで作った二つのインスタンスは、それぞれの残高を持ちます。コンストラクタは生成時に実行され、thisは現在のインスタンスを指します。staticなフィールドを残高に使うと、個々の財布ではなくクラスで共有する値になってしまいます。

メソッドは業務上の操作を表す

すべてのフィールドにsetメソッドを作るだけでは、自由な書き換えと大差ありません。depositのように目的を表す名前を使うと、不変条件を保ちやすくなります。不変条件とは「残高が負ではない」など、操作の前後で常に守りたい性質です。

一方、名前と金額を運ぶだけの値にはrecordも便利です。recordの各構成要素はfinalですが、中に可変リストを持てば、そのリストまで自動的に変更不能になるわけではありません。深い不変性は第15回で扱います。

練習と解答

練習:出金メソッドを追加してください。0以下の額と残高を超える額を拒否し、失敗したときは残高を変えない仕様にします。

解答例:if (amount <= 0 || amount > yen) throw new IllegalArgumentException("出金できません"); の後で yen -= amount; とします。先に引いてからエラーにすると、失敗後の状態が壊れます。検査、計算、更新の順番までが設計です。残高と同額の出金は成功し、0になることも確認します。

公式資料

クラスとオブジェクトを参照できます。


Java全20回の目次 | 前の回 | 次の回

このブラウザでは Web Speech API が利用できません。

1 / 15 · 停止中