Python | 2週間で身につく、アプリを作りながら学ぶPythonの基本 - 12日目

Python Python
スポンサーリンク

12日目のゴールとテーマ

12日目のテーマは 「クラス同士を組み合わせて“アプリの世界観”を作る」 です。
昨日は「Task という1つのクラス」を作りました。
今日はそこから一歩進んで、

  • クラスを“複数”作る
  • クラス同士が協力してアプリを動かす
  • 「管理する側のクラス」を作ってアプリの構造を整理する

という、アプリ設計の本質に踏み込みます。

ここまで来ると、あなたはもう「文法を覚える段階」ではなく、
「アプリをどう設計するか」を考える段階に入っています。


クラスを増やすと何が嬉しいのか

「役割ごとにクラスを分けると、アプリが読みやすくなる」

昨日の Task クラスは、
「タスク1件分の情報と、そのタスクに関する処理」をまとめたものでした。

でも、アプリ全体を考えると、
「タスクをまとめて管理する役割」も必要になります。

例えば、

  • タスクを追加する
  • タスク一覧を返す
  • タスクを削除する
  • ファイルに保存する
  • ファイルから読み込む

こういった“管理者”の役割は、Task クラスには向きません。

そこで登場するのが TaskManager クラス です。

Task は「1件分」
TaskManager は「全体を管理する人」

この分担ができると、アプリの構造が一気に整理されます。


TaskManager クラスの最小形を作る

「タスクリストを持つクラス」

まずは、最小限の TaskManager を作ってみます。

class TaskManager:
    def __init__(self):
        self.tasks = []

    def add(self, task):
        self.tasks.append(task)

    def all(self):
        return self.tasks
Python

ここでのポイントを丁寧に見ていきます。

__init__ の中で self.tasks = []
→ TaskManager は「タスクのリスト」を持つ存在。

add(self, task)
→ Task オブジェクトを受け取ってリストに追加する。

all(self)
→ タスク一覧を返す。

これだけでも、辞書やリストを直接扱うよりずっと読みやすくなります。


TaskManager に「削除」機能を足す

「番号を指定して削除する」

タスク管理アプリでは、削除もよく使います。
TaskManager に削除メソッドを追加してみましょう。

class TaskManager:
    def __init__(self):
        self.tasks = []

    def add(self, task):
        self.tasks.append(task)

    def all(self):
        return self.tasks

    def delete(self, index):
        if 0 <= index < len(self.tasks):
            del self.tasks[index]
            return True
        else:
            return False
Python

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

  • 削除できたら True
  • 範囲外なら False

という「結果を返す」設計にしていることです。

こうしておくと、呼び出し側で

if manager.delete(2):
    print("削除しました")
else:
    print("その番号のタスクはありません")
Python

のように分岐できます。


TaskManager に「保存・読み込み」を持たせる

「管理者がデータの出し入れを担当する」

TaskManager がタスク全体を管理するなら、
ファイル保存・読み込みも TaskManager の仕事にできます。

import datetime

class TaskManager:
    def __init__(self):
        self.tasks = []

    def add(self, task):
        self.tasks.append(task)

    def all(self):
        return self.tasks

    def delete(self, index):
        if 0 <= index < len(self.tasks):
            del self.tasks[index]
            return True
        return False

    def save(self, filename):
        with open(filename, "w", encoding="utf-8") as file:
            for task in self.tasks:
                line = task.name + "," + task.deadline.isoformat() + "\n"
                file.write(line)

    def load(self, filename, task_class):
        self.tasks = []

        try:
            with open(filename, "r", encoding="utf-8") as file:
                for line in file:
                    line = line.strip()
                    if line == "":
                        continue

                    name, date_text = line.split(",")
                    year, month, day = map(int, date_text.split("-"))
                    deadline = datetime.date(year, month, day)

                    task = task_class(name, deadline)
                    self.tasks.append(task)

        except FileNotFoundError:
            self.tasks = []
Python

ここでの深掘りポイントは、

TaskManager が Task クラスを知らないようにしている

load の引数に task_class を渡しているのがポイントです。

manager.load("tasks.txt", Task)
Python

と呼び出すことで、

  • TaskManager は「タスクの作り方」を知らない
  • Task クラスの変更に TaskManager が巻き込まれない

という“ゆるい結びつき”が実現します。

これはアプリ設計でとても大事な考え方です。


Task クラスと TaskManager クラスを組み合わせる

「役割分担」が見えてくる

ここまで来ると、アプリの構造はこうなります。

Task
→ 1件分の情報とロジックを持つ

TaskManager
→ 複数の Task をまとめて管理する

main(アプリ本体)
→ メニューを出し、TaskManager に仕事を依頼する

この3層構造は、現実のアプリでもよく使われる形です。


12日目のミニアプリ:クラス2つで作るタスク管理

「Task × TaskManager × メニュー」の三位一体

以下は全体のイメージです(コードは短縮版)。

import datetime

class Task:
    def __init__(self, name, deadline):
        self.name = name
        self.deadline = deadline

    def status_text(self):
        today = datetime.date.today()
        diff = (self.deadline - today).days
        if diff > 0:
            return f"あと {diff} 日"
        elif diff == 0:
            return "今日が締切!"
        else:
            return f"期限切れ({-diff} 日過ぎ)"


class TaskManager:
    def __init__(self):
        self.tasks = []

    def add(self, task):
        self.tasks.append(task)

    def all(self):
        return self.tasks

    def delete(self, index):
        if 0 <= index < len(self.tasks):
            del self.tasks[index]
            return True
        return False


def main():
    manager = TaskManager()

    while True:
        print("1: 追加  2: 一覧  3: 削除  0: 終了")
        choice = input("番号を選んでください: ")

        if choice == "1":
            name = input("タスク名: ")
            date_text = input("締切(YYYY-MM-DD): ")
            y, m, d = map(int, date_text.split("-"))
            task = Task(name, datetime.date(y, m, d))
            manager.add(task)

        elif choice == "2":
            for i, task in enumerate(manager.all(), start=1):
                print(i, task.name, "→", task.status_text())

        elif choice == "3":
            index = int(input("削除する番号: ")) - 1
            if manager.delete(index):
                print("削除しました")
            else:
                print("その番号はありません")

        elif choice == "0":
            break


main()
Python

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

  • main は「メニューと入力」だけ
  • TaskManager は「タスク全体の管理」
  • Task は「1件分のロジック」

という役割分担ができていることです。


クラスを増やすとアプリが“世界”になる

「登場人物が増えると、アプリが自然に読める」

クラスを使うと、コードが「物語」になります。

Task
→ タスクという“登場人物”

TaskManager
→ タスクを管理する“司令塔”

main
→ アプリ全体の“舞台監督”

こういう構造になると、
コードを読むときに「何がどこにあるか」が自然に分かるようになります。

これは、辞書やリストだけでは絶対に得られない感覚です。


12日目で一番大事な感覚

「クラスは“役割を持った登場人物”」

今日あなたに持ってほしい感覚はこれです。

クラスはただの文法ではなく、
アプリの中に「役割を持った登場人物」を作るための仕組みです。

Task は「タスクというキャラクター」
TaskManager は「タスクを管理するキャラクター」

こうやって登場人物を増やしていくと、
アプリの構造がどんどん自然になっていきます。


12日目のまとめ

今日のキーポイントを短く整理すると、

  • クラスは「役割を持った登場人物」
  • Task は「1件分の情報とロジック」
  • TaskManager は「複数の Task を管理する存在」
  • main は「アプリ全体の流れを決める場所」
  • クラスを分けると、アプリの構造が読みやすくなる

もし余裕があれば、次の機能を TaskManager に足してみてください。

  • 「締切が近いタスクだけを返す」
  • 「名前で検索する」
  • 「優先度で並び替える」

ここまで来ると、あなたはもう「クラスを使ってアプリを設計できる人」です。
13日目・14日目では、この力をさらに“アプリとして完成させる方向”に伸ばしていきます。

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