Java | 1 日 90 分 × 7 日アプリ学習 初級編:クラス分割アプリ

APP Java
スポンサーリンク

4日目のゴール

4日目のテーマは
「クラスの中身を“きれいに整理して”、main から“気持ちよく使える形”にすること」 です。

ここまでであなたはすでに、

クラスは役割を持った登場人物
main はスタート地点であり、シナリオを書く人
クラス同士を会話させるイメージ

をつかんでいます。

4日目ではここから一歩進んで、

クラスの中身(フィールド・コンストラクタ・メソッド)を意識して整理する
「外から触ってほしい部分」と「隠したい部分」を分けるイメージを持つ
main から見たときに「使いやすいクラス」になっているかを考える

ここを、3日目の「買い物アプリ」を少し進化させながら固めていきます。


復習:3日目のクラス構成をもう一度イメージする

3日目の買い物ミニアプリは、こんな役割分担でした。

Item は「商品1つの情報(名前・価格)」
Cart は「商品をためて、合計金額を計算する」
Person は「人(名前)と、その人のカート」を持ち、買い物する
Main は「これらを new して、流れ(シナリオ)を書く」

今日は、この構成を「中身の整理」と「外との付き合い方」という視点で見直します。


クラスの中身を3つに分けて考える

クラスの中身は、大きく次の3つに分けられます。

フィールド
そのクラスが持つ「状態」「データ」。
例:名前、価格、カートの中身など。

コンストラクタ
そのクラスを「正しい状態」で生み出すための入り口。
例:必須の情報を渡さないと new できないようにする。

メソッド
そのクラスができる「振る舞い」「処理」。
例:買う、合計を計算する、表示するなど。

4日目では、
「このクラスは new された瞬間に、ちゃんと使える状態になっているか?」
「外から直接いじらせたくないものを、ちゃんと隠せているか?」
という視点で、この3つを整えていきます。


Item クラスを“ちゃんとした1人前”にする

コンストラクタで「必須情報」を強制する

3日目の Item は、こうでした。

public class Item {
    String name;
    int price;
}
Java

このままだと、こういうことができてしまいます。

Item item = new Item();
// name も price も設定しないまま使えてしまう
Java

「名前も値段もない商品」が存在できるのは、ちょっと変です。
そこで、「Item を作るときには必ず名前と価格を渡させる」ようにします。

public class Item {
    String name;
    int price;

    Item(String name, int price) {
        this.name = name;
        this.price = price;
    }
}
Java

こうすると、Item はこういう形でしか作れません。

Item apple = new Item("りんご", 120);
Item bread = new Item("パン", 180);
Java

ここでの重要ポイントは、

「このクラスは、こういうふうに new されるのが正しい」という形を、コンストラクタで決めてしまう

ということです。

main から見ても、
new Item("りんご", 120) のほうが、
「名前と値段を持った商品を作っているんだな」と一目で分かります。


「隠す」という発想を持つ

なんでもかんでも外から触れると壊れやすくなる

3日目の Cart は、こういう形でした。

public class Cart {
    Item[] items;
    int count;

    Cart(int maxSize) { ... }
    void add(Item item) { ... }
    int totalPrice() { ... }
    void showItems() { ... }
}
Java

このままだと、main からこういうことができます。

Cart cart = new Cart(10);
cart.items[0] = null;
cart.count = 100;
Java

Cart の中身を、外から好き放題いじれてしまいます。
これは「クラスの中のルールを壊される」危険な状態です。

ここで出てくるのが、
「カプセル化(隠す)」 という考え方です。

「このクラスの中身は、このクラス自身だけが直接いじれる」
「外からは、用意されたメソッドを通してだけ操作してもらう」

というルールを作ることで、
クラスの中の整合性を守りやすくなります。


Cart クラスをカプセル化してみる

フィールドを private にして、メソッド経由で操作させる

Cart を、こう書き直してみます。

public class Cart {
    private Item[] items;
    private int count;

    public Cart(int maxSize) {
        items = new Item[maxSize];
        count = 0;
    }

    public void add(Item item) {
        if (count >= items.length) {
            System.out.println("これ以上カートに入れられません。");
            return;
        }
        items[count] = item;
        count++;
    }

    public int totalPrice() {
        int sum = 0;
        for (int i = 0; i < count; i++) {
            sum += items[i].price;
        }
        return sum;
    }

    public void showItems() {
        System.out.println("カートの中身:");
        for (int i = 0; i < count; i++) {
            System.out.println("- " + items[i].name + " : " + items[i].price + "円");
        }
    }
}
Java

ここでの変更点と意味を深掘りします。

private Item[] items;private int count;
Cart の中身(配列と個数)は「Cart の中だけで使うもの」と宣言しています。
外のクラス(Main や Person)からは直接触れません。

public Cart(int maxSize)
コンストラクタは「外から呼んでほしい」ので public にしています。
Cart を new するときに、最大サイズを必ず指定させています。

public void add(...), public int totalPrice(), public void showItems()
Cart に対して「外からお願いしていいこと」を public メソッドとして公開しています。
外からは「add して」「合計教えて」「中身見せて」としか言えません。

これにより、main からはこういうことができなくなります。

cart.items[0] = null;   // コンパイルエラー
cart.count = 100;       // コンパイルエラー
Java

代わりに、こういう書き方になります。

cart.add(apple);
int total = cart.totalPrice();
cart.showItems();
Java

このほうが、
「Cart に対して何をしているのか」が明確で、
クラスの中のルールも壊されにくくなります。


Person クラスも「外との境界」を意識して整える

フィールドを隠して、コンストラクタとメソッドで使わせる

Person も同じように整えてみます。

public class Person {
    private String name;
    private Cart cart;

    public Person(String name, Cart cart) {
        this.name = name;
        this.cart = cart;
    }

    public void buy(Item item) {
        System.out.println(name + " は " + item.name + " をカートに入れました。");
        cart.add(item);
    }

    public void showCart() {
        System.out.println("=== " + name + " のカート ===");
        cart.showItems();
        int total = cart.totalPrice();
        System.out.println("合計: " + total + "円");
    }
}
Java

ここでのポイントはこうです。

private String name; private Cart cart;
Person の「中身」は、Person 自身だけが直接いじれるようにしています。
外から person.name = "花子"; のように書けなくなります。

public Person(String name, Cart cart)
Person を new するときに、必ず名前と Cart を渡させています。
「名前なしの人」「カートを持っていない人」は作れません。

public void buy(...), public void showCart()
Person に対して「外からお願いしていいこと」を public メソッドとして公開しています。
main からは「買って」「カート見せて」としか言えません。

これにより、
Person の中のルール(必ずカートを持っている、名前があるなど)が守られます。


main から見た「使いやすさ」を確認する

main は“登場人物を並べて、シナリオを書く”だけにしたい

ここまで整えたクラスを使って、main を書き直してみます。

public class Main {
    public static void main(String[] args) {
        Cart cart = new Cart(10);

        Person person = new Person("太郎", cart);

        Item apple = new Item("りんご", 120);
        Item bread = new Item("パン", 180);
        Item milk = new Item("牛乳", 200);

        person.buy(apple);
        person.buy(bread);
        person.buy(milk);

        person.showCart();
    }
}
Java

main がやっていることは、もうこれだけです。

Cart を1つ作る
Person を1人作る(名前と Cart を渡す)
Item をいくつか作る(名前と価格を渡す)
Person に「これ買って」「カート見せて」とお願いする

Cart の中身の配列も、
Person のフィールドも、
main からは一切触っていません。

ここでの本質は、

main は「登場人物を new して、関係をつないで、順番を決める」だけ
ロジックの中身は、全部クラス側に閉じ込める

という構造になっていることです。


「クラスの役割」と「main との関係」を言葉で説明してみる

4日目の時点で、
このアプリをこう説明できたらかなり良いです。

Item は「商品1つの情報(名前・価格)を持つクラス」
必ず名前と価格を渡して new する。
外からは、作って渡すだけ。

Cart は「商品をためて、合計金額を計算し、中身を表示するクラス」
中身の配列やカウントは private。
外からは add・totalPrice・showItems だけを呼べる。

Person は「人を表し、自分の Cart を使って買い物するクラス」
名前と Cart を渡して new する。
外からは buy と showCart だけを呼べる。

Main は「これらのクラスを new して、シナリオを書くクラス」
中身のロジックには踏み込まず、「誰に何をさせるか」だけを書く。

この「説明できるかどうか」が、
クラス設計が頭に入っているかの良いチェックになります。


4日目で絶対に押さえてほしい本質

今日いちばん大事なのは、
クラスをこういう目で見られるようになることです。

クラスの中身は「フィールド・コンストラクタ・メソッド」で構成される
コンストラクタで「正しい作られ方」を決める
フィールドはできるだけ private にして、メソッド経由で操作させる

そして、

main は「中身の実装」を知らなくても、
public なコンストラクタとメソッドだけ見て、
クラスを“道具”として使える状態が理想。

ここまで来たあなたは、
もう「クラスをなんとなく分ける人」ではなく、
「クラスの中身と外との境界を意識して設計できる人」 です。

5日目以降は、
ここに「メソッドの分割」「責任のさらに細かい切り分け」や、
もう少し複雑なミニアプリを重ねていくと、
一気に「現場で通用するクラス設計」の感覚に近づいていきます。

タイトルとURLをコピーしました