5日目のゴール
5日目のテーマは
「クラス分割を“なんとなく”から、“自分で設計できるレベル”に一段引き上げること」 です。
ここまでであなたはすでに、
クラスは役割を持った登場人物
main はスタート地点であり、シナリオを書く人
フィールド・コンストラクタ・メソッドを意識してクラスを組み立てる
private と public で「中身」と「外との境界」を分ける
というところまで来ています。
5日目ではここから一歩進んで、
「処理のかたまり」をどのクラスのどのメソッドに置くか考える
main に残すべき処理と、クラス側に移すべき処理を見極める
クラス同士の“会話”を、より自然な形に整える
これを、昨日までの「買い物アプリ」を少し発展させながらやっていきます。
まずは4日目の状態を“俯瞰”してみる
4日目の時点で、買い物アプリはこんな構成でした。
Item
名前と価格を持つ。
コンストラクタで必ず name と price を受け取る。
Cart
中に Item をためる。
add で追加、totalPrice で合計、showItems で中身表示。
配列やカウンタは private。
Person
名前と Cart を持つ。
buy でカートに商品を入れ、showCart で中身と合計を表示。
フィールドは private。
Main
Cart・Person・Item を new して、
「誰が何を買うか」「いつカートを表示するか」という流れだけを書く。
ここまでは、「クラスの中身をきれいにして、main から気持ちよく使える形」にする、というところまで来ました。
5日目は、
「処理の置き場所」と「責任の分け方」を、もう一段だけ細かく見ていきます。
main に“残りがちな処理”を見つける
4日目の 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ここで、少し想像してみてください。
商品が10個、20個と増えたら?
Person が2人、3人と増えたら?
「おすすめセット」をまとめて買う機能を付けたくなったら?
main に「商品を1つずつ new して、1つずつ buy する」コードが増えていくと、
また main が“太り始める”気配があります。
5日目でやりたいのは、
この「太り始める main から、処理のかたまりをクラス側に移す」感覚です。
「まとまった処理」に名前をつけて、メソッドにする
例:Person に「まとめ買い」のメソッドを持たせる
今の main では、こう書いています。
person.buy(apple);
person.buy(bread);
person.buy(milk);
Javaこれを、「まとめ買い」という1つの意味のある動きとして扱いたくなったとします。
そのときにやることはシンプルで、
「この3行は、誰の責任の処理か?」
「この3行に名前をつけるとしたら、何と呼ぶか?」
を考えて、それをメソッドにすることです。
「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 buyAll(Item[] items) {
System.out.println(name + " はまとめて商品をカートに入れます。");
for (Item item : items) {
buy(item);
}
}
public void showCart() {
System.out.println("=== " + name + " のカート ===");
cart.showItems();
int total = cart.totalPrice();
System.out.println("合計: " + total + "円");
}
}
Javaそして 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);
Item[] items = { apple, bread, milk };
person.buyAll(items);
person.showCart();
}
}
Javaここでの本質は、
「意味のある処理のかたまり」に名前をつけて、
それを“ふさわしいクラスのメソッド”として移す
ということです。
「どのクラスの責任か?」を考える癖をつける
さっきの例でいうと、
複数の商品を順番に買う
これは「Person がやること」なので、Person のメソッドにした
という判断をしました。
同じように、他の処理も見ていきます。
例えば、「合計金額に消費税を足して表示したい」とします。
今は Person の showCart がこうなっています。
public void showCart() {
System.out.println("=== " + name + " のカート ===");
cart.showItems();
int total = cart.totalPrice();
System.out.println("合計: " + total + "円");
}
Javaここに「税込み金額」を足したくなったら、
どこに書くのが自然でしょうか。
合計金額を計算しているのは Cart
Person は「Cart に合計を聞いて、表示している」
なので、「税率をどうするか」「税込みをどう計算するか」は、
Cart 側に寄せるのが自然です。
Cart に「税込み合計」を計算させる
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 int totalPriceWithTax(double taxRate) {
int total = totalPrice();
double taxed = total * (1.0 + taxRate);
return (int) taxed;
}
public void showItems() {
System.out.println("カートの中身:");
for (int i = 0; i < count; i++) {
System.out.println("- " + items[i].name + " : " + items[i].price + "円");
}
}
}
Javaそして Person の showCart を、こう変えます。
public void showCart() {
System.out.println("=== " + name + " のカート ===");
cart.showItems();
int total = cart.totalPrice();
int totalWithTax = cart.totalPriceWithTax(0.1); // 10% として
System.out.println("小計: " + total + "円");
System.out.println("税込: " + totalWithTax + "円");
}
Javaここでの重要ポイントは、
「合計金額の計算ロジック」は Cart の責任
Person は「Cart に聞いて、結果を表示するだけ」
という分担になっていることです。
もし将来、税率の扱いを変えたくなっても、
Cart の中だけを直せば済みます。
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);
Item[] items = { apple, bread, milk };
person.buyAll(items);
person.showCart();
}
}
Java5日目で意識してほしいのは、
「main に残っている処理のうち、“意味のあるかたまり”はないか?」
「それは、どのクラスの責任として移せそうか?」
と自分に問いかけることです。
もし、main にこういうコードが増え始めたら要注意です。
同じような処理が何度も出てくる
if や for が増えて、main が長くなっていく
「これ、誰の仕事なんだろう?」と自分でもよく分からない
そういうときこそ、
「この処理に名前をつけるとしたら?」
「その名前は、どのクラスに属するのが自然?」
と考えて、メソッドとしてクラス側に移すタイミングです。
5日目のミニアプリ完成形をまとめて眺める
ここまでの変更を反映したコードを、もう一度まとめます。
public class Item {
String name;
int price;
Item(String name, int price) {
this.name = name;
this.price = price;
}
}
Javapublic 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 int totalPriceWithTax(double taxRate) {
int total = totalPrice();
double taxed = total * (1.0 + taxRate);
return (int) taxed;
}
public void showItems() {
System.out.println("カートの中身:");
for (int i = 0; i < count; i++) {
System.out.println("- " + items[i].name + " : " + items[i].price + "円");
}
}
}
Javapublic 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 buyAll(Item[] items) {
System.out.println(name + " はまとめて商品をカートに入れます。");
for (Item item : items) {
buy(item);
}
}
public void showCart() {
System.out.println("=== " + name + " のカート ===");
cart.showItems();
int total = cart.totalPrice();
int totalWithTax = cart.totalPriceWithTax(0.1);
System.out.println("小計: " + total + "円");
System.out.println("税込: " + totalWithTax + "円");
}
}
Javapublic 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);
Item[] items = { apple, bread, milk };
person.buyAll(items);
person.showCart();
}
}
Javaこの構成を見て、
「誰が何を担当しているか」「main は何をしていて、何をしていないか」を、
自分の言葉で説明できるかどうかが、5日目のチェックポイントです。
5日目で絶対に押さえてほしい本質
今日いちばん大事なのは、
クラス分割をこういう目で見られるようになることです。
処理のかたまりに「名前」をつける
その名前が一番しっくりくるクラスに、メソッドとして置く
main に残るのは「登場人物を用意して、順番を決める」だけ
そして、
「これは誰の責任の処理か?」と考える癖をつける
「main に書きっぱなしの処理」を見つけたら、クラス側に移せないか考える
ここまで来たあなたは、
もう「クラスを使える人」ではなく、
「クラスの責任と main との関係を意識して設計できる人」 です。
6日目・7日目では、
この感覚を別の題材にも当てはめてみたり、
少しだけ仕様を複雑にしても破綻しないクラス設計を試していくと、
一気に“現場で通用するコードの感覚”に近づいていきます。

