第7章 カプセル化
モジュールとして分割するべきかを決める基準として、最も大事なことは他の部分から隠蔽すべき秘密を持っているかどうか
レコードのカプセル化
レコード構造はプログラミング言語の一般的な機能
関連するデータを一緒にグループ化して、緩いデータの群れの代わりに、意味のあるデータ単位を提供する
しかし、単純なレコード構造には、レコードに格納されている値と計算した値の明確な区別を共用されるなどの欠点もある
変更可能なデータなら、オブジェクトにする方が良い
手順
- レコードを保持する変数に変数のカプセル化を施す
- 変数の中身をレコードをラップするクラスに置き換える
- テストする
- レコードそのものではなく、オブジェクトを返す関数を用意する
- レコードの使用箇所ごとにレコードを返す処理を、オブジェクトを返すようにする
- 生データへのアクセサと、レコードをそのまま返す関数を消す
- テスト
- レコード自体がフィールドの構造体である場合、レコードのカプセル化とコレクションのカプセル化を再帰的に施すことを検討する
コレクションのカプセル化
コレクションの変数へのアクセスはカプセル化していても、getterがコレクションそのものを返してしまうと、コレクションを保持するクラスを介さずにその中身を変更できてしまう
一般的な解決方法は、取得用のメソッドを用意しそれにコピーを返すようにすること
手順
- コレクションの参照がカプセル化されていないなら、変数のカプセル化をする
- 要素を削除・追加するための関数をコレクションに追加する
- 静的チェック
- 全てのコレクションの参照を探し置き換える
- コレクションのgetterを変更し、保護されたビューを返すようにする
- テスト
オブジェクトによるプリミティブの置き換え
単純な表示以上のことをするなら、ちょっとしたデータでもクラスにするべき
手順
- 変数のカプセル化ができていないなら施す
- データ地のための単純な値クラスを作る
- 静的チェック
- setterを作る
- getterを値クラスの結果を返すようにする
- テスト
- 処理内容がわかるように、もとのアクセサに関数名の変更を検討する
- 新たなオブジェクトの役割が、値オブジェクトなのか参照オブジェクト7日を明確にする
- 値オブジェクトにする場合、参照から値への変更
- 参照オブジェクトにする場合、値から参照への変更
問い合わせによる一時変数の置き換え
変数の代わりに関数を使うことで、似通った関数で計算ロジックが重複するのを防げる
問い合わせによる一時変数の置き換えに適した一次関数はほんの一部に限られる
手順
- 一時変数の値は、それが使われる前に確定していることを確認する
- 一時変数が読み取り専用でないときは、読み取り専用にする
- テスト
- 一時変数への代入を関数として抽出する
- テスト
- 変数のインライン化をし、取り除く
クラスの抽出
手順
- クラスの責務をどのように切り出すのかを決める
- 切り出した責務を記述するための新たな子クラスを作る
- 元の親クラスのインスタンスを生成するときに、新たな子クラスのインスタンスも作るようにする
- 移動したい各フィールドにフィールドの移動をする
- メソッドを子クラスに移動するために、関数の移動をする
- 両クラスのインターフェースを見直す
- 不要なメソッドの削除や名前の変更など
- 新たな子クラスのインスタンスを公開するか決める
- 公開する場合、参照から値への変更をすることを検討する
クラスのインライン化
クラスが役割を終えて、存在価値がなくなったときに行う
他には2つのクラスをリファクタリングをして特性の配置を変えたいとき
この場合は、一つのクラスにまとめてからクラスの抽出を行う
手順
- インライン先のクラスに、元のクラスのpublic関数に対応する関数を作る
- 元のクラスのメソッドへの参照を全て変更する
- すべての関数とデータを元のクラスからインライン先のクラスに移す
- 元のクラスを削除する
委譲の隠蔽
委譲先のオブジェクトがインターフェースを変更すると、呼び出し元のオブジェクトも変更する必要がある
これらの依存関係を断ち切るために、委譲先オブジェクトを隠すための委譲用メソッドを作る
手順
- 委譲先のオブジェクトの各ソッドに対応する単純な委譲用メソッドを作る
- 呼び出し元を修正し、委譲先を呼び出すようにする
- クライアントで委譲先のオブジェクトへのアクセスが必要な部分がなくなったら、アクセサを消す
- テスト
仲介人の除去
委譲の隠蔽を使いすぎると、オブジェクトはただの仲介人になってしまう
その場合、仲介人の除去で消す
手順
- 委譲先オブジェクトを取得するgetterを作る
- 委譲メソッドを仕様クライアントごとに、委譲メソッドへの呼び出しをgetterから始まる、メソッドチェーンで置き換える
アルゴリズムの置き換え
アルゴリズムに手を加えて動作を少し変えたいとき、まずは必要な変更がしやすい形に置き換えてから行うほうがかんたんな場合もある
手順
- 完結した機能を果たすように、置き換え前のコードを整える
- この機能だけを使ったテストを用意して、振る舞いを把握する
- 変わりのアルゴリズムを用意する
- 静的チェック
- テストをして、出力結果を比較する
感想
レコード構造とは…
ハッシュとかみたいなもの?
レコード wikipedia によると構造体とからしい
rubyならStruct
とか
コレクションのカプセル化について
言語仕様の問題な気がする
これが問題になるのは参照渡しになっているケースっぽい?
値渡しなら、関係ない気がする