3日目のゴール
3日目のテーマは
「クラスを“ただ分ける”から、“ちゃんと責任を分ける”にレベルアップすること」 です。
1〜2日目であなたはすでに、
クラス=設計図、main=スタート地点&司令塔
クラスに“役割”を持たせる
main に書きすぎず、クラスに仕事を渡す
という感覚をつかみ始めています。
3日目ではここから一歩進んで、
クラスを「現実の登場人物」に対応させる
クラス同士を「会話させる」イメージを持つ
main は「シナリオを書く人」に徹する
これを、少しだけ“アプリっぽい”題材で固めていきます。
今日の題材:買い物ミニアプリで考える
「人・商品・カート」という3つの役割
いきなり難しいことはしません。
シンプルに「買い物」を題材にします。
登場人物を、現実の世界からそのまま持ってきます。
人(お客さん)
商品
カート(買い物かご)
これを Java のクラスにすると、こうなります。
Person … お客さんを表すクラス
Item … 商品を表すクラス
Cart … カート(中に商品をためて、合計金額を計算する)
そして main は、
Person を作る
Item をいくつか用意する
Cart を作る
Person に「カートに商品を入れてもらう」
最後に合計金額を表示する
という「シナリオを書く人」になります。
Item クラスを作る
「商品」という1つの概念に集中させる
まずは一番シンプルな「商品」から。
public class Item {
String name;
int price;
}
ここでは、あえてシンプルにしています。
name … 商品名
price … 価格(整数でOK)
このクラスの役割を一言で言うと、
「商品1つの情報(名前と値段)を持つだけのクラス」
です。
まだメソッドはありません。
「データの箱」としてのクラスも、立派な役割です。
Cart クラスを作る
「商品をためて、合計金額を出す」役割
次に、カートを表すクラスを作ります。
public class Cart {
Item[] items;
int count;
Cart(int maxSize) {
items = new Item[maxSize];
count = 0;
}
void add(Item item) {
if (count >= items.length) {
System.out.println("これ以上カートに入れられません。");
return;
}
items[count] = item;
count++;
}
int totalPrice() {
int sum = 0;
for (int i = 0; i < count; i++) {
sum += items[i].price;
}
return sum;
}
void showItems() {
System.out.println("カートの中身:");
for (int i = 0; i < count; i++) {
System.out.println("- " + items[i].name + " : " + items[i].price + "円");
}
}
}
ここでの役割を丁寧に整理します。
Cart は「商品をためて、合計金額を計算する」クラスです。
中身の実装は配列とカウンタですが、本質はそこではありません。
Cart の責任は、
商品を追加する(add)
合計金額を計算する(totalPrice)
中身を表示する(showItems)
という「カートとしての振る舞い」をまとめて持つことです。
main から見たときに、
「カートに商品を入れて」「合計を教えて」「中身を見せて」
とお願いできれば、それで十分です。
Person クラスを作る
「カートを持って買い物する人」
次に、お客さんを表す Person クラスを作ります。
public class Person {
String name;
Cart cart;
Person(String name, Cart cart) {
this.name = name;
this.cart = cart;
}
void buy(Item item) {
System.out.println(name + " は " + item.name + " をカートに入れました。");
cart.add(item);
}
void showCart() {
System.out.println("=== " + name + " のカート ===");
cart.showItems();
int total = cart.totalPrice();
System.out.println("合計: " + total + "円");
}
}
ここでの役割を深掘りします。
Person は「人の情報(名前)」と「その人のカート」を持つクラスです。
そして、「買う(buy)」と「カートの中身を確認する(showCart)」という動きを持っています。
重要なのは、
Person 自身は「合計金額の計算ロジック」を持っていない
計算は Cart に任せている
Person は「Cart に仕事を振る」立場
という分担です。
これが、クラス同士が「会話している」状態です。
Person「この商品をカートに入れて」
Cart「OK、入れたよ」
Person「カートの中身見せて、合計も教えて」
Cart「中身はこれで、合計はこれだよ」
というイメージで捉えてください。
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();
apple.name = "りんご";
apple.price = 120;
Item bread = new Item();
bread.name = "パン";
bread.price = 180;
Item milk = new Item();
milk.name = "牛乳";
milk.price = 200;
person.buy(apple);
person.buy(bread);
person.buy(milk);
person.showCart();
}
}
ここで main がやっていることを、言葉で整理します。
Cart を1つ作る
Person を1人作り、その人に Cart を渡す
Item をいくつか作る
Person に「これ買って」「これも買って」と指示する
最後に「カートの中身見せて」とお願いする
main は、
「登場人物を new して、関係をつないで、順番を決める」
という役割だけを担っています。
合計金額の計算ロジックも、
カートの中身の表示も、
商品名や価格の扱いも、
全部クラス側に任せています。
これが、
「main はシナリオを書く人、クラスは役者」
という構造です。
もしクラス分割しなかったらどうなるか
main に全部書いた世界を想像してみる
同じ「買い物アプリ」を、クラス分割せずに main だけで書くとどうなるか。
商品名と価格を全部変数で持つ
配列やリストを main の中で直接操作する
合計金額の計算も main の中で for 文を書く
表示も main の中で全部 println
最初は動きます。
でも、少し仕様が変わると一気にしんどくなります。
カートを2つにしたい(家族分など)
Person を2人にしたい
Item の情報を増やしたい(カテゴリ、在庫数など)
全部 main に書いていると、
「どこを直せばいいのか分からない」「同じようなコードが増える」
という状態になります。
クラス分割の本当の価値は、
「変更に強くなること」
「main を短く保てること」
です。
3日目のミニアプリ完成形
全コードをもう一度まとめて眺める
ここまでのコードを、1つずつ並べておきます。
public class Item {
String name;
int price;
}
public class Cart {
Item[] items;
int count;
Cart(int maxSize) {
items = new Item[maxSize];
count = 0;
}
void add(Item item) {
if (count >= items.length) {
System.out.println("これ以上カートに入れられません。");
return;
}
items[count] = item;
count++;
}
int totalPrice() {
int sum = 0;
for (int i = 0; i < count; i++) {
sum += items[i].price;
}
return sum;
}
void showItems() {
System.out.println("カートの中身:");
for (int i = 0; i < count; i++) {
System.out.println("- " + items[i].name + " : " + items[i].price + "円");
}
}
}
public class Person {
String name;
Cart cart;
Person(String name, Cart cart) {
this.name = name;
this.cart = cart;
}
void buy(Item item) {
System.out.println(name + " は " + item.name + " をカートに入れました。");
cart.add(item);
}
void showCart() {
System.out.println("=== " + name + " のカート ===");
cart.showItems();
int total = cart.totalPrice();
System.out.println("合計: " + total + "円");
}
}
public class Main {
public static void main(String[] args) {
Cart cart = new Cart(10);
Person person = new Person("太郎", cart);
Item apple = new Item();
apple.name = "りんご";
apple.price = 120;
Item bread = new Item();
bread.name = "パン";
bread.price = 180;
Item milk = new Item();
milk.name = "牛乳";
milk.price = 200;
person.buy(apple);
person.buy(bread);
person.buy(milk);
person.showCart();
}
}
この構成を見て、
「誰が何を担当しているか」を一言で言えるかどうかが、3日目のチェックポイントです。
3日目で絶対に押さえてほしい本質
今日いちばん大事なのは、
クラスと main の関係をこう説明できることです。
Item … 商品1つの情報を持つクラス
Cart … 商品をためて、合計金額を計算するクラス
Person … 人を表し、Cart を使って買い物するクラス
Main … これらのクラスを new して、関係をつなぎ、シナリオ(流れ)を書くクラス
そして、
main にロジックを詰め込むのではなく、
「この処理はどのクラスの責任か?」と考えて、
できるだけクラス側に寄せていく。
この感覚が入っていれば、
4日目以降で「メソッドの分割」「フィールドの隠蔽(カプセル化)」に進んだとき、
一気に理解が楽になります。
もうあなたは、
「クラスをなんとなく使う人」ではなく、
「クラスに役割を与えて、main からシナリオを書く人」 になり始めている。
ここから先は、どんどん“現実の世界”をコードに落としていくフェーズです。

