* オブジェクトとデータ構造の違いをきちんと理解するのが重要
* オブジェクト指向言語であっても、その使い分けを意識する必要があると感じた
* デメテルの法則
* DTOに関しては、よく直面することがあるため扱いに注意すべきだし、DTOと別のオブジェクトを作るべきだと思った
6章 オブジェクトとデータ構造
データ抽象化
- 単に変数との間にgetter/setterのような関数の層を入れるのは実装の隠蔽とはならない
- 実装の隠蔽とは、抽象化である
- データの詳細を公開するのでなく、データを抽象化された形式で表現したい
- 軽い気持ちでgetter/setterを用意してはならず、熟考が必要
データ/オブジェクトの非対称性
オブジェクト指向、手続き型の書き方にはメリット・デメリットがあり、その違いを理解しておくことが重要。
- 手続き型
- 新たな関数を既存のデータ構造に影響を与えず追加が可能
- 新たなデータ構造を追加するには、既存のすべての関数の変更が必要
- オブジェクト指向型
- 既存の関数を変えることなく、新たなクラスの追加が可能
- 新たな関数の追加には、すべてのクラスの変更が必要
デメテルの法則
デメテルの法則
- オブジェクトを使用する場合、そのオブジェクトの内部について知るべきではない
オブジェクトはアクセサを通して内部のデータ構造を公開してはならない。内部構造を公開するこになるため。
クラスの C のメソッド f は、次のオブジェクトのメソッドのみを呼び出すべき
* C そのもの
* f で生成されたオブジェクト
* f の引数で渡されたオブジェクト
* C のインスタンス変数に保持されたオブジェクト
電車の衝突
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
- あたかも連結された車両のように見えるので、電車の衝突と呼ばれることがある。
- 一般には避けるべきと考えられている
Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
final String outputDir = scratchDir.getAbsolutePath();
これがデメテルの法則に違反しているかどうかは、ctxt, Options, ScartchDirがオブジェクトなのか、データ構造なのかによる。
混血児
オブジェクトとデータ構造の混血児が生成されることがあるが、関数もデータ構造の追加もどちらも困難にするため、作ってはならない。
隠蔽構造
さきほどのctxt, options,scratchDirが実際に振る舞いを持ったオブジェクトだった場合、どうすべきか?本来やろうとしていたことを見直すべき。異なるレベルの詳細を混在させるべきでなく、この場合だとctxtにやらせる。
データ転送オブジェクト
典型的なデータ構造クラスは関数をもたずpublic変数のみをもったもの。データ転送オブジェクト(Data Transfer Object, DTO)と呼ばれることがある。
よくあるのがDBから読み込んだ最初の段階など。
「Bean」の場合だと、private変数がgetter/setterで操作され、カプセル化しているように見えるが、
通常は何の利点もない
アクティブレコード
アクティブレコードはDTOの特殊形態であり、これはデータ構造。データベーステーブルなどデータソースの直接の写像である。
これをオブジェクトのように扱おうとしてビジネスルールを持ったメソッドを追加するのは、「混血児」を作ることになるため、やるべきではない。
解決策は、ビジネスルールを持ったオブジェクトを別に用意すること。
内部データ(「おそらくは、アクティブレコードのインスタンス」)はオブジェクトの中に隠蔽する。
結論
オブジェクトとデータ構造の違いをきちんと理解し、使い分ける必要がある。
コメント