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

APP Java
スポンサーリンク

6日目のゴール

6日目のテーマは
「クラス分割の考え方を“別の題材”にも適用できるようになること」 です。

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

クラスは役割を持った登場人物
main はスタート地点であり、シナリオを書く人
フィールド・コンストラクタ・メソッドを意識してクラスを組み立てる
処理のかたまりに名前をつけて、ふさわしいクラスに置く

というところまで来ています。

6日目では、
「買い物アプリ」から少し離れて、
“タスク管理ミニアプリ” を題材にしながら、

クラスの役割を自分で決める
main から見たときに“気持ちよく使えるAPI”を意識する
クラス同士の会話をシンプルに保つ

この感覚を、もう一段深く身体に染み込ませていきます。


今日の題材:タスク管理ミニアプリを設計する

まずは“言葉だけ”で設計してみる

いきなりコードに行かず、
まずは「どんな登場人物がいるか」を言葉で整理します。

やりたいことはシンプルです。

タスクを作る
タスクを完了にする・未完了に戻す
タスク一覧を表示する

ここから、クラス候補を考えます。

タスクそのものを表すクラス
タスクをまとめて管理するクラス
アプリ全体の流れを書く main

これを Java のクラスにすると、こうなります。

Task … 1件のタスク(タイトル・完了フラグ)を表す
TaskList … 複数のタスクを持ち、追加・一覧・状態変更を担当する
Main … TaskList を使って、シナリオ(どのタスクを作ってどう操作するか)を書く

この「現実の世界 → クラス」に落とす一歩目が、6日目の一番大事なところです。


Task クラスを設計する

「タスク1件」をちゃんと1人前のクラスにする

まずは、タスク1件を表すクラスから。

public class Task {
    private String title;
    private boolean done;

    public Task(String title) {
        this.title = title;
        this.done = false;
    }

    public void markDone() {
        done = true;
    }

    public void markUndone() {
        done = false;
    }

    public boolean isDone() {
        return done;
    }

    public String getTitle() {
        return title;
    }

    public void show() {
        String status = done ? "[完了]" : "[未完了]";
        System.out.println(status + " " + title);
    }
}
Java

ここでのポイントを深掘りします。

コンストラクタでタイトルを必須にしている
new Task("掃除する") のように、
「タイトルなしのタスク」が作れないようにしています。
作られた瞬間に done = false(未完了)という“正しい初期状態”になります。

markDonemarkUndone で状態変更をカプセル化している
外から task.done = true; のように直接いじらせず、
「完了にする」「未完了に戻す」という“意味のある操作”として提供しています。

show が「自分の表示の仕方」を知っている
Task 自身が「自分をどう表示するか」を知っているので、
main や他のクラスは task.show(); と呼ぶだけで済みます。

Task の役割を一言で言うと、
「タスク1件の状態と、その状態に関する操作をまとめたクラス」
です。


TaskList クラスを設計する

「タスクをまとめて管理する人」を作る

次に、複数のタスクを扱うクラスです。

public class TaskList {
    private Task[] tasks;
    private int count;

    public TaskList(int maxSize) {
        tasks = new Task[maxSize];
        count = 0;
    }

    public void add(Task task) {
        if (count >= tasks.length) {
            System.out.println("これ以上タスクを追加できません。");
            return;
        }
        tasks[count] = task;
        count++;
    }

    public void showAll() {
        System.out.println("=== タスク一覧 ===");
        if (count == 0) {
            System.out.println("タスクはありません。");
            return;
        }
        for (int i = 0; i < count; i++) {
            System.out.print((i + 1) + ". ");
            tasks[i].show();
        }
    }

    public void markDone(int index) {
        if (!isValidIndex(index)) {
            System.out.println("その番号のタスクは存在しません。");
            return;
        }
        tasks[index].markDone();
    }

    public void markUndone(int index) {
        if (!isValidIndex(index)) {
            System.out.println("その番号のタスクは存在しません。");
            return;
        }
        tasks[index].markUndone();
    }

    private boolean isValidIndex(int index) {
        return index >= 0 && index < count;
    }
}
Java

ここでの本質を整理します。

TaskList は「タスクの配列」と「現在の件数」を内側に持っている
配列やカウンタは private にして、外から直接いじれないようにしています。
外からは「追加」「一覧表示」「完了・未完了の切り替え」だけをお願いできます。

add が「タスクを追加する」という意味のある操作になっている
配列のどこに入れるか、カウンタをどう増やすか、
そういった“細かい実装”は TaskList の中に閉じ込めています。

markDonemarkUndone は「何番目のタスクか」を受け取る
TaskList が「何番目にどの Task がいるか」を知っていて、
実際の状態変更は Task に任せています。
ここでも「責任の分担」がはっきりしています。

isValidIndex を private メソッドにしている
「インデックスが有効かどうかのチェック」という
“細かいけど何度も使う処理”を、
TaskList の中に小さくまとめています。

TaskList の役割を一言で言うと、
「複数の Task をまとめて管理し、番号で操作できるようにするクラス」
です。


main は“シナリオを書く人”に徹する

登場人物を用意して、流れだけを書く

ここまでのクラスを使って、main を書いてみます。

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

        Task t1 = new Task("部屋を掃除する");
        Task t2 = new Task("メールを返信する");
        Task t3 = new Task("Java の勉強をする");

        taskList.add(t1);
        taskList.add(t2);
        taskList.add(t3);

        System.out.println("最初の状態:");
        taskList.showAll();

        taskList.markDone(0);
        taskList.markDone(2);

        System.out.println();
        System.out.println("一部完了にしたあと:");
        taskList.showAll();

        taskList.markUndone(0);

        System.out.println();
        System.out.println("1番目を未完了に戻したあと:");
        taskList.showAll();
    }
}
Java

main がやっていることを、言葉で整理します。

TaskList を1つ作る
Task をいくつか作る
TaskList にタスクを追加する
「何番目を完了にするか」「どのタイミングで一覧を表示するか」という流れを書く

ここで重要なのは、

main は「配列の添字」や「件数の管理」を一切知らない
Task の done フラグにも直接触れていない
TaskList と Task の public メソッドだけを使っている

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


「処理の置き場所」をもう一段だけ考えてみる

例:完了タスクだけを表示したくなったら?

ここで、仕様を少しだけ変えてみます。

「完了したタスクだけを表示したい」

このとき、どこに処理を書くのが自然でしょうか。

Task は「自分が完了かどうか」を知っている
TaskList は「タスクを全部持っている」
main は「どのタイミングで何を表示するか」を決める

なので、「完了タスクだけを表示する」という処理は、
TaskList の責任にするのが自然です。

TaskList に、こういうメソッドを追加できます。

public void showDoneTasks() {
    System.out.println("=== 完了したタスク ===");
    boolean hasAny = false;
    for (int i = 0; i < count; i++) {
        if (tasks[i].isDone()) {
            System.out.print((i + 1) + ". ");
            tasks[i].show();
            hasAny = true;
        }
    }
    if (!hasAny) {
        System.out.println("完了したタスクはありません。");
    }
}
Java

そして main からは、こう呼べます。

System.out.println();
System.out.println("完了したタスクだけ表示:");
taskList.showDoneTasks();
Java

ここでの本質は、

「完了タスクだけを表示する」という“意味のある処理”に名前をつけて、
それを TaskList のメソッドとして置いた

ということです。

もしこれを main にベタ書きしてしまうと、

配列を for で回す
isDone() を呼ぶ
show() を呼ぶ
フラグで「1件もなかったか」を管理する

といった細かい処理が main にあふれます。
それを TaskList に閉じ込めることで、
main は「いつ呼ぶか」だけを考えればよくなります。


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

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

Task
タスク1件を表すクラス。
タイトルと完了フラグを持ち、
「完了にする」「未完了に戻す」「自分を表示する」といった操作を提供する。

TaskList
複数の Task をまとめて管理するクラス。
追加・一覧表示・番号指定での完了/未完了切り替え・完了タスクだけの表示など、
「タスク全体に対する操作」を担当する。

Main
Task と TaskList を new して、
「どのタスクを作るか」「どの順番で操作するか」というシナリオを書くクラス。
配列やフラグの細かい扱いには踏み込まず、
public メソッドだけを使ってアプリの流れを組み立てる。

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


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

今日いちばん大事なのは、
「クラス分割の考え方を、別の題材にも自分で適用できた」 という経験です。

現実の世界から登場人物(クラス候補)を見つける
それぞれに「一言で言える役割」を与える
フィールド・コンストラクタ・メソッドで、その役割を形にする
main は「登場人物を new して、順番を決める」だけにする

そして、

「この処理は誰の責任か?」
「この処理に名前をつけるとしたら?」
「その名前が一番しっくりくるクラスはどれか?」

と考えながら、処理の置き場所を決めていく。

ここまで来たあなたは、
もう「クラスを教科書通りに書く人」ではなく、
「自分で題材を決めて、クラスの役割と main との関係を設計できる人」 です。

7日目は、この感覚を使って、
「小さなアプリ全体を自分で設計する」ところまで一度通してみる。
そこまで行くと、クラス分割はもう“怖い概念”じゃなくて、
“自分の武器”になっているはずです。

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