10日目のゴールとテーマ
10日目のテーマは
「これまでの要素を全部つなげて、“小さな本格アプリ”としてまとめる」 です。
ここまでであなたは、
変数・配列・ArrayList
if・for・while
メソッド
クラスとオブジェクト
カプセル化(private / getter / setter)
クラス同士の関係(Task と TaskManager)
を一通り触ってきました。
今日は、これらを「バラバラの知識」で終わらせず、
1つの“ミニアプリ”として形にしていきます。
題材は引き続き ToDo 系ですが、
今日は少しだけ機能を増やして、
タスクに「優先度」を持たせる
タスクを「未完了だけ」「完了だけ」で絞り込んで表示する
タスクを削除できるようにする
といった、現実のアプリに近い要素を足していきます。
今日の完成イメージ
「タスク管理アプリ・ちょっと本格版」
10日目で目指すアプリは、ざっくり言うとこんな感じです。
タスクには
タイトル
完了フラグ
優先度(1〜3など)
を持たせる。
アプリとしては、
タスクを追加する
タスク一覧を表示する
未完了タスクだけ表示する
完了タスクだけ表示する
タスクを完了にする
タスクを削除する
といった操作ができるようにします。
ここまで来ると、
「コンソール版だけど、ちゃんとしたタスクアプリ」
と言っていいレベルになります。
Taskクラスを「優先度付き」に拡張する
新しいフィールドを足しても、クラスなら怖くない
まずは Task クラスに「優先度」を足します。
優先度は、
1 = 低
2 = 中
3 = 高
のようなイメージで数値で持つことにします。
public class Task {
private String title;
private boolean done;
private int priority; // 1〜3で表す
public Task(String title, int priority) {
setTitle(title);
setPriority(priority);
this.done = false;
}
public String getTitle() {
return this.title;
}
public boolean isDone() {
return this.done;
}
public int getPriority() {
return this.priority;
}
public void setTitle(String title) {
if (title == null || title.isEmpty()) {
System.out.println("タイトルが空です。変更を無視します。");
return;
}
this.title = title;
}
public void setPriority(int priority) {
if (priority < 1 || priority > 3) {
System.out.println("優先度は1〜3で指定してください。変更を無視します。");
return;
}
this.priority = priority;
}
public void complete() {
this.done = true;
}
public void printWithNumber(int number) {
String status = done ? "完了" : "未完了";
String priorityLabel = toPriorityLabel(priority);
System.out.println(number + ": " + title + " / 状態: " + status + " / 優先度: " + priorityLabel);
}
private String toPriorityLabel(int priority) {
if (priority == 1) {
return "低";
} else if (priority == 2) {
return "中";
} else if (priority == 3) {
return "高";
} else {
return "不明";
}
}
}
Javaここでの重要ポイントを深掘りします。
優先度を int で持っている
1〜3以外は setter で弾いている
→ 「優先度のルール」を Task の中に閉じ込めている
toPriorityLabel を private にしている
→ 外からは呼ばせない「内部用のメソッド」
→ 表示用のラベル変換ロジックを1か所にまとめている
コンストラクタで setPriority(priority); を呼んでいる
→ 作るときも、あとから変えるときも、同じルールが適用される
クラスを使うと、「フィールドを増やす」が怖くなくなります。
Task を使っている側は、基本的にコンストラクタと getter / setter だけ意識していればよく、
内部のルールは Task に任せられます。
TaskManagerを「機能拡張」する
追加・一覧・完了に加えて、「削除」と「絞り込み表示」
次に、TaskManager を少しパワーアップさせます。
import java.util.ArrayList;
public class TaskManager {
private ArrayList<Task> tasks;
public TaskManager() {
this.tasks = new ArrayList<>();
}
public void addTask(String title, int priority) {
Task task = new Task(title, priority);
tasks.add(task);
System.out.println("タスクを追加しました。");
}
public void printAllTasks() {
if (tasks.isEmpty()) {
System.out.println("タスクは登録されていません。");
return;
}
System.out.println("=== すべてのタスク ===");
for (int i = 0; i < tasks.size(); i++) {
Task task = tasks.get(i);
task.printWithNumber(i + 1);
}
}
public void printIncompleteTasks() {
System.out.println("=== 未完了のタスク ===");
int count = 0;
for (int i = 0; i < tasks.size(); i++) {
Task task = tasks.get(i);
if (!task.isDone()) {
task.printWithNumber(i + 1);
count++;
}
}
if (count == 0) {
System.out.println("未完了のタスクはありません。");
}
}
public void printCompletedTasks() {
System.out.println("=== 完了したタスク ===");
int count = 0;
for (int i = 0; i < tasks.size(); i++) {
Task task = tasks.get(i);
if (task.isDone()) {
task.printWithNumber(i + 1);
count++;
}
}
if (count == 0) {
System.out.println("完了したタスクはありません。");
}
}
public void completeTask(int number) {
int index = number - 1;
if (index < 0 || index >= tasks.size()) {
System.out.println("その番号のタスクは存在しません。");
return;
}
Task task = tasks.get(index);
if (task.isDone()) {
System.out.println("そのタスクはすでに完了しています。");
} else {
task.complete();
System.out.println("タスク「" + task.getTitle() + "」を完了にしました。");
}
}
public void removeTask(int number) {
int index = number - 1;
if (index < 0 || index >= tasks.size()) {
System.out.println("その番号のタスクは存在しません。");
return;
}
Task removed = tasks.remove(index);
System.out.println("タスク「" + removed.getTitle() + "」を削除しました。");
}
}
Javaここでの重要ポイントを整理します。
printIncompleteTasks と printCompletedTasks
→ 同じ tasks リストから、「条件に合うものだけ」を表示している
→ 絞り込みロジックを TaskManager に閉じ込めている
removeTask
→ 削除も TaskManager の責任
→ インデックスの範囲チェックもここでやる
TaskManager は、「タスクに関する操作の窓口」としてだいぶ育ってきました。
Mainクラスで「メニューを増やす」
ユーザーから見た“機能”として整理する
次に、Main クラスでメニューを拡張します。
import java.util.Scanner;
public class Main {
public static void printMenu() {
System.out.println("=== タスク管理アプリ(10日目版) ===");
System.out.println("1: タスクを追加する");
System.out.println("2: すべてのタスクを表示する");
System.out.println("3: 未完了のタスクだけ表示する");
System.out.println("4: 完了したタスクだけ表示する");
System.out.println("5: タスクを完了にする");
System.out.println("6: タスクを削除する");
System.out.println("0: 終了する");
System.out.print("番号を選んでください: ");
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
TaskManager manager = new TaskManager();
while (true) {
printMenu();
int choice = scanner.nextInt();
scanner.nextLine(); // 改行を読み飛ばす
if (choice == 0) {
System.out.println("アプリを終了します。");
break;
} else if (choice == 1) {
System.out.print("タスクのタイトルを入力してください: ");
String title = scanner.nextLine();
System.out.print("優先度を入力してください(1:低, 2:中, 3:高): ");
int priority = scanner.nextInt();
scanner.nextLine();
manager.addTask(title, priority);
} else if (choice == 2) {
manager.printAllTasks();
} else if (choice == 3) {
manager.printIncompleteTasks();
} else if (choice == 4) {
manager.printCompletedTasks();
} else if (choice == 5) {
System.out.print("完了にするタスクの番号を入力してください: ");
int number = scanner.nextInt();
scanner.nextLine();
manager.completeTask(number);
} else if (choice == 6) {
System.out.print("削除するタスクの番号を入力してください: ");
int number = scanner.nextInt();
scanner.nextLine();
manager.removeTask(number);
} else {
System.out.println("その番号は無効です。");
}
System.out.println();
}
}
}
Javaここでのポイントは、
Main は「ユーザーとの会話」だけを担当している
TaskManager に「何をしてほしいか」を伝えているだけ
という構造になっていることです。
タスクの持ち方
優先度のルール
絞り込みのロジック
などは、すべて Task / TaskManager 側に閉じ込められています。
「機能を足す」ときの思考パターン
どのクラスの責任かをまず考える
例えば、
「優先度の高いタスクだけ表示したい」
という機能を足したくなったとします。
このとき、いきなり Main にコードを書き始めるのではなく、
これは誰の責任か?
TaskManager がやるべきか?
Task に何かメソッドを足すべきか?
と考えます。
優先度で絞り込むのは「タスク全体の中から条件に合うものを選ぶ」処理なので、
TaskManager の責任にするのが自然です。
例えば、こういうメソッドを TaskManager に足せます。
public void printHighPriorityTasks() {
System.out.println("=== 優先度「高」のタスク ===");
int count = 0;
for (int i = 0; i < tasks.size(); i++) {
Task task = tasks.get(i);
if (task.getPriority() == 3) {
task.printWithNumber(i + 1);
count++;
}
}
if (count == 0) {
System.out.println("優先度「高」のタスクはありません。");
}
}
JavaMain 側は、メニューに1行足して、manager.printHighPriorityTasks(); を呼ぶだけです。
このように、
新しい機能を思いついたら
→ まず「どのクラスの責任か」を考える
→ そのクラスにメソッドを足す
という流れを取れるようになると、
アプリを「壊さずに育てる」感覚が身についてきます。
10日目で一番大事な感覚
「バラバラの文法」から「1つのアプリの設計」へ
今日あなたに持ってほしい感覚はこれです。
ここまで学んできたものは、
単なる「文法の寄せ集め」ではありません。
変数・if・for・メソッド・クラス・ArrayList・カプセル化・クラス同士の関係
これらは全部、「アプリという1つの生き物」を形作るパーツです。
Task という“登場人物”
TaskManager という“管理者”
Main という“司令塔”
それぞれが役割を持ち、
お互いに関係し合いながら、
1つのタスク管理アプリとして動いています。
「文法を覚える」から
「アプリの構造を考える」へ。
ここが、プログラミングが一気に面白くなるポイントです。
10日目のまとめと、11日目への予告
今日やったことを短く整理すると、
Task に「優先度」という新しいフィールドを足した
setter の中で「1〜3だけOK」というルールを入れた
TaskManager に「絞り込み表示」「削除」などの機能を足した
Main は「ユーザーとのやりとり」と「TaskManagerへの指示」に集中した
新しい機能を足すときに、「どのクラスの責任か」を考える流れを体験した
11日目からは、
このミニアプリをベースにしつつ、
例外処理(エラーへの向き合い方)や、
少しだけファイル入出力(保存・読み込み)にも触れていきます。
「動けばいい」から一歩進んで、
「壊れにくく、ちゃんと使えるアプリ」に近づけていきましょう。
