JavaScript | 1 日 120 分 × 7 日アプリ学習:クラス設計アプリ(オブジェクト指向)

Web APP JavaScript
スポンサーリンク

7日目のゴールと今日やること

7日目のテーマは
「class・カプセル化・責務分離を“自分の設計基準”として言語化すること」です。

ここまでで、メモアプリを通して
クラスを増やし、状態を増やし、保存も入れてきました。
今日は「設計を終わらせる」のではなく、
「これから自分でアプリを設計するときの軸」をはっきりさせる日です。

そのために、

class をどう切るか
カプセル化をどこまで徹底するか
責務分離をどう判断するか

を、メモアプリを題材に“言葉で整理”していきます。


これまで作ってきた構造を「レイヤー」で見直す

ドメイン層の役割を言葉にする

ドメイン層には、Memo と MemoList がいました。

Memo は
「1つのメモという概念」を表現するクラスです。
id、text、done、priority などの状態を持ち、
それらに関するルール(バリデーション)と振る舞い(完了・未完了・優先度変更など)を
自分の中に閉じ込めています。

ここで重要なのは、
Memo は「画面のこと」「保存先のこと」を一切知らない、という点です。
Memo が知っているのは「メモとしてどうあるべきか」だけです。

MemoList は
「メモの集まり」を扱うクラスです。
追加、検索、削除、ID 発行、優先度での絞り込みなど、
“複数の Memo をまとめて扱う操作”を担当します。

MemoList もまた、DOM や localStorage の存在を知りません。
知っているのは「集まりとしてどう振る舞うか」だけです。

これが、ドメイン層の責務です。

アプリケーション層とインフラ層の役割

MemoAppController は
「ユーザーの操作」と「ドメインの操作」をつなぐ司令塔です。

ボタンが押された
入力欄に文字が入った
リストの項目がクリックされた

といったイベントを受け取り、
どの MemoList のメソッドを呼ぶかを決め、
その結果を DOM に反映します。

MemoStorage は
「どこに・どう保存するか」を担当するクラスです。
localStorage を使うことを知っているのは、このクラスだけ。
保存形式(JSON の形)も、このクラスの中に閉じ込められています。

Controller は「いつ保存するか」を決め、
Storage は「どう保存するか」を決め、
ドメインは「何を保存するか」を決める。
この三者の分担が、アプリ全体の骨組みになっています。


class を「箱」ではなく「契約」として見る

public メソッドは「約束」であるという感覚

7日目で一番深く持ってほしい感覚は、
「class の public メソッドは“外の世界との契約”だ」ということです。

Memo で言えば、
getText、setText、isDone、markDone、markUndone、getPriority、setPriority などが
外から呼んでよい窓口です。

この窓口に対して、
「こう呼べば、こう振る舞う」という約束を守り続けることが、
クラス設計の信頼性になります。

逆に、#text や #done や #priority は
「外から触ってはいけない領域」です。
ここはクラスの内側の事情であり、
将来どう変えてもよい“実装の自由”がある場所です。

カプセル化とは、
「契約(public)と実装(private)を分けること」
と言い換えることができます。

責務分離は「契約の数を増やしすぎない」ことでもある

1つのクラスに何でもかんでも詰め込むと、
public メソッドが増えすぎて、契約だらけになります。

そうなると、
どこか1つを変えただけで、
大量の呼び出し元に影響が出てしまいます。

責務分離は、
「クラスごとの契約を小さく保つための分割作業」
とも言えます。

Memo は「1つのメモ」に関する契約だけ。
MemoList は「メモの集まり」に関する契約だけ。
MemoStorage は「保存と読み込み」に関する契約だけ。
MemoAppController は「アプリの起動とイベント処理」に関する契約だけ。

こうやって、
クラスごとの契約を小さく、はっきりさせておくと、
アプリは壊れにくく、育てやすくなります。


具体例で見る「設計の判断基準」

新機能例 1:タグ機能を足したくなったとき

「メモにタグを付けたい」という要求を考えてみます。

例えば、
「仕事」「プライベート」「勉強」などのタグを複数付けたい。

このとき、設計の軸はこうなります。

タグという概念は「メモの一部」か?
→ はい。Memo に tags フィールドを持たせるのが自然。

タグのルール(文字数制限、重複禁止など)はどこに書くか?
→ Memo の中に validateTags のようなメソッドを作る。

特定のタグを持つメモだけを集める処理はどこか?
→ MemoList に filterByTag のようなメソッドを作る。

タグの入力 UI(チェックボックスやテキスト入力)はどこか?
→ HTML と MemoAppController の責務。

タグを保存・読み込みするときの JSON 形式はどこで決めるか?
→ MemoStorage の責務。

こうやって、
「新しい要素が出てきたときに、どのクラスの責任かを割り振る」
という思考が、そのまま設計作業になります。

新機能例 2:ソート順を変えたいとき

「優先度の高いメモを上に表示したい」
「完了していないメモを先に表示したい」

このときの判断はこうです。

ソートの基準(priority や done)はどこが知っているべきか?
→ Memo が状態を持ち、MemoList が集まりとして並べ替える。

UI で「ソート順を選ぶセレクトボックス」を置くのは誰の仕事か?
→ HTML と Controller。

ソート結果を画面に反映するのは誰か?
→ Controller が MemoList から並び替え済みの配列を受け取り、DOM を描画する。

ここでも、
「ドメインのルール」と「UI の都合」を混ぜない、
という軸が効いてきます。


「class・カプセル化・責務分離」を自分の言葉にする

あなたなりの一文にしてみる

最後に、7日間やってきたことを
あえて自分の言葉で一文にしてみてほしいです。

例えば、こんな感じです。

class とは
「ある役割を持ったオブジェクトの、状態と振る舞いをまとめた設計図」。

カプセル化とは
「外から触っていいところと、触ってはいけないところを分けて、
ルールを中に閉じ込めること」。

責務分離とは
「1つのクラスに何役もやらせず、
役割ごとにクラスを分けて、契約を小さく保つこと」。

このレベルまで言葉に落ちていれば、
もう「class の文法を知っている人」ではなく、
「class で設計できる人」になっています。


7日目の締め:これからクラス設計をどう使っていくか

ここまでのメモアプリは、
オブジェクト指向の練習としてはかなり濃い内容でした。

でも本当に大事なのは、
このアプリそのものではなく、

新しい機能を思いついたときに
「どのクラスの責任か?」と自然に考えられること。
新しい状態やルールを足したくなったときに
「どこに閉じ込めるべきか?」と考えられること。
UI の都合でドメインを汚さない、という感覚を持ち続けること。

この3つです。

もし次に何か作るなら、
メモアプリじゃなくてもいい。
タスク管理でも、家計簿でも、習慣トラッカーでもいい。

そのときに、
class・カプセル化・責務分離を
「またあのメモアプリみたいに分けてみるか」と
思い出してくれたら、それだけでこの7日間は大成功です。

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