読書「Clean Code」6章

* オブジェクトとデータ構造の違いをきちんと理解するのが重要
  * オブジェクト指向言語であっても、その使い分けを意識する必要があると感じた
* デメテルの法則
* 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の特殊形態であり、これはデータ構造。データベーステーブルなどデータソースの直接の写像である。

これをオブジェクトのように扱おうとしてビジネスルールを持ったメソッドを追加するのは、「混血児」を作ることになるため、やるべきではない。

解決策は、ビジネスルールを持ったオブジェクトを別に用意すること。

内部データ(「おそらくは、アクティブレコードのインスタンス」)はオブジェクトの中に隠蔽する。

結論

オブジェクトとデータ構造の違いをきちんと理解し、使い分ける必要がある。

コメント

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