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日間は大成功です。


