はじめに
@nqounetです。
シリーズ「本棚アプリで覚える集合体の巡回」の第2回です。
前回の振り返り
前回は、本棚アプリの基礎となる2つのクラスを作成しました。
Bookクラス —title(タイトル)とauthor(著者)の属性を持つBookShelfクラス — 複数の本を管理する集合体。add_book、get_book_at、get_lengthメソッドを提供する
これらのクラスを使って、本棚に本を追加し、個別に取り出す機能を実装しました。
今回のお題:すべての本を一覧表示したい
本棚に登録したすべての本を一覧表示する機能を追加してみましょう。一見簡単そうに見えますが、この実装を通じて「カプセル化」について深く考える機会になります。
素朴なアプローチ:books配列に直接アクセスする
まず、最も素朴なアプローチを試してみます。BookShelfのbooks属性に直接アクセスして、forループで回す方法です。
| |
このコードは動作します。しかし、ここには重大な問題が潜んでいます。
カプセル化の破壊
オブジェクト指向プログラミングにおける「カプセル化」とは、オブジェクトの内部構造を隠蔽し、外部には必要なインターフェースだけを公開する考え方です。
flowchart LR
subgraph 問題のあるアプローチ
Client1[利用者コード] -->|"$shelf->books->@*"| Internal[内部配列に直接アクセス]
Internal -->|カプセル化の破壊| BookShelf1[BookShelf]
end
上記のコードの問題点を整理します。
BookShelfの内部が「配列」であることを外部から知っている必要があるbooks属性に直接アクセスしている- 配列のデリファレンス記法(
->@*)を使っている
これは、本棚の「引き出しを開けて中身を直接見ている」ようなものです。本棚の設計者は、本を配列で管理することを内部の実装詳細として隠したいはずです。しかし、外部のコードがこの実装詳細に依存してしまっています。
なぜこれが問題なのか
将来、BookShelfの内部構造が変更になった場合を考えてみます。
- 本を配列ではなくハッシュで管理するようになった
- データベースから都度取得するようになった
- ページネーションを導入して一部の本だけをメモリに保持するようになった
このような変更が入ると、$shelf->books->@*と書いているすべての箇所を修正する必要があります。これは保守性の面で大きな問題です。
改善版:メソッド経由でアクセスする
前回作成したget_lengthとget_book_atメソッドを使ってみましょう。
| |
このコードは、books属性に直接アクセスしていません。BookShelfが提供するメソッドのみを使用しています。これは先ほどのコードより改善されています。
この改善版でも残る問題
しかし、このアプローチにもまだ問題があります。
- 「インデックスでアクセスできる」という内部構造への依存が残っている
- ループの書き方(0から始まる、lengthを使う)を利用側が意識している
- 巡回のロジックが利用側に散らばる
flowchart LR
subgraph 改善版でも残る依存
Client2[利用者コード] -->|"get_length() + get_book_at(i)"| Index[インデックス操作の知識が必要]
Index --> BookShelf2[BookShelf]
end
本棚の実装が「配列」から「連結リスト」や「データベース」に変わった場合、この書き方は使えなくなる可能性があります。
理想的な形
本当に欲しいのは、以下のような形です。
- 「次の本を取得する」という操作だけを知っていればよい
- 本棚の内部構造を一切意識しない
- 本棚側が巡回方法を完全にコントロールする
これを実現する方法については、次回以降で詳しく見ていきます。
完成コード
今回の内容を反映した完成コードを以下に示します。2つのアプローチを比較できるようにしています。
| |
実行結果
| |
まとめ
- カプセル化とは、オブジェクトの内部構造を隠蔽し、外部には必要なインターフェースだけを公開する考え方である
$shelf->books->@*のように内部の配列に直接アクセスするとカプセル化が崩れるget_lengthとget_book_atを使う方法は改善だが、「インデックスでアクセスする」という前提への依存が残る- 内部構造に依存したコードは、将来の変更で修正が必要になるリスクがある
次回予告
今回、本棚のすべての本を一覧表示する際に「カプセル化」の問題に直面しました。メソッドを使う改善版でも、まだ「インデックスでアクセスする」という内部構造への依存が残っています。
次回は、この問題を解決するための新しい仕組みを導入します。本棚の内部構造を一切知らなくても、すべての本を順番に取り出せる方法を探ります。
お楽しみに。
