Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

第30章 デザインパターン #36

Open
at-grandpa opened this issue Jan 11, 2018 · 12 comments
Open

第30章 デザインパターン #36

at-grandpa opened this issue Jan 11, 2018 · 12 comments

Comments

@at-grandpa
Copy link
Owner

  • 様々な問題はあるが、よく見ると一般的な問題であり、解決方法も一般的な場合が多い
    • パターンをいっぱい知っていることは良いことだなぁ
  • GoF本は、「設計はある一つのフェーズ」である事が前提となっている
    • リファクタリングを設計行為として捉えていない
  • TDDにおける設計は、デザパタを少し違う視点で捉えないといけない
    • どんな視点なんだろう
  • TDDのデザパタは以下の二つの側面がある
    • テストで使われる
    • リファクタリングで使われる
@at-grandpa
Copy link
Owner Author

Commandパターン

  • 処理の呼び出しがメソッド呼び出しよりも複雑になってきた場合
    • 処理のためのオブジェクトを作成し、それを起動するようにする
  • 処理の実行が複雑、とはどういことか
    • 単純なメソッド呼び出しではなく、、、
      • メソッド呼び出しの他にロギングもしたい
      • 処理の実行を遅延したい
      • など
  • その複雑なしょりをまとめてオブジェクトにしてしまう
    • 大げさな仕組みなど不要、オブジェクトで良い
    • 処理の実行をメッセージで行うよりも、少しだけ明確で編集可能にする
    • 一般的なrunメソッドで実行する

どんな問題を解決するのか

  • 複雑な処理や似たような処理が複数ある場合
  • 処理の追加をしたときに、変更箇所が大量にできてしまう場合

解決したらどうなるか

  • 新しい処理のオブジェクトを生成するだけ
    • 共通処理は修正しなくてよい

どう解決しているのか

  • 処理自身をオブジェクト化してしまい、共通のインターフェースを持たせる
    • あとは共通処理に食わせるだけ
  • 結局、「複数ある処理オブジェクト」に「共通のインターフェース」を持たせているだけか
    • いろんなパターンがあるが、結局は共通のインターフェースが肝なだけでは?

@at-grandpa
Copy link
Owner Author

Value Object パターン

  • 別名参照問題を解消する
    • 数字の「5」など、他の箇所で「5」のオブジェクトを書き換えられたら、参照先が変わってしまうので、自分の持っている「5」も変更されてしまう
  • これを防ぐ
  • オブジェクトの操作は、かならず新しいオブジェクトを返す。決して内部状態は変えない。
  • オブジェクトの特性である「内部状態」というのもを固定してしまう
    • オブジェクト以下の存在を作る
  • 毎回新しいオブジェクトを作成するので、パフォーマンスに影響はある
  • コードが追いやすく、デバッグしやすい
  • 等価性比較を実装しなければならない

どんな問題を解決するのか

  • 広く共有されるものの、同一インスタンスであることは重要ではない場合
  • 別名参照問題を避けたい時

解決したらどうなるか

  • value-objectの内部状態は変わらないので、安心して使える

どう解決しているのか

  • 内部状態を変更できないようにする
  • オブジェクトへの何らかの操作は、必ず新しいオブジェクトを返す

@at-grandpa
Copy link
Owner Author

at-grandpa commented Jan 11, 2018

Null Object パターン

  • 特殊な状況をオブジェクトで表現したい
    • 専用のオブジェクトを作り、通常のオブジェクトと同じプロトコルにする
  • これはcrystalでもよくぶち当たった問題だ
  • nilを変数の可能性として持たせたくない場合、空のオブジェクトを作っていた
    • 特殊なオブジェクトだ
  • こうすることで、その後のコードからnilチェックを無くすことができる
    • crystalはこれを強制している

どんな問題を解決するのか

  • 特殊な状況における処理が多い

解決したらどうなるか

  • 特殊な状況に依存したコードを消せる

どう解決しているのか

  • 特殊な状況をオブジェクトで表し、プロトコルを一緒にする

@at-grandpa
Copy link
Owner Author

at-grandpa commented Jan 11, 2018

Template Method パターン

  • 処理の順序だけを規定し、拡張は開かれた状態にしたい
    • 他のメソッドを順番に呼び出すだけのメソッドを書く
    • 他のメソッドはabstractメソッドにする
  • コードを書いていると、典型的な順序に出会う
    • 入力、処理、出力
    • メッセージ送信、応答の受信
    • など
  • 順序は保ちつつ、拡張性を提供したい
  • このパターンは、最初から設計するよりは、後で実装から導き出されることが多い
    • わかる
  • TDDの途中でも出てきたくらいだ

どんな問題を解決するのか

  • 処理順序は決めたまま、拡張性を維持したい

解決したらどうなるか

  • 処理順序は決めたまま、拡張性を維持できる

どう解決しているのか

  • 親クラスには処理順序を書いただけのメソッドを用意する
  • 子クラスで各メソッドの実装をする

@at-grandpa
Copy link
Owner Author

at-grandpa commented Jan 11, 2018

Pluggable Object パターン

  • バリエーションはどう表現すればよいか
    • シンプルなのはif文
    • でも、増殖してしまうよね
      • 図形が円の場合とそれ以外の場合の条件分岐を 1 カ所でも書いてしまうと、その 条件分岐は増殖を始める。
  • TDDは重複の排除が掟なので、増殖する条件分岐は排除せねばならない
  • 条件分岐を二つ見つけたら、Pluggable Object パターンの導入を始めるタイミングだ
  • if文を横断した各条件の処理を一つのオブジェクトにし、一回にif文でオブジェクトを選択し、あとの処理は共通処理を使う
    • ほら、これもインターフェースの共通化だ
    • commandパターンと似たようなことをしている

どんな問題を解決するのか

  • ある複数の事柄の条件分岐が、至る所に発生している場合

解決したらどうなるか

  • 事柄ごとのif文は1箇所になる

どう解決しているのか

  • 各if文に関係しているものをオブジェクトにまとめてしまう
  • if文はオブジェクトの選択の1回のみ
  • あとは共通のインターフェースを実装しているので、if文は存在しなくなる

@at-grandpa
Copy link
Owner Author

Pluggable Selector パターン

  • インスタンスごとに異なる振る舞いをさせたい
  • 処理を追いにくいのが難点

どんな問題を解決するのか

  • 各サブクラスにひとつずつしかインターフェースのメソッドがない場合
  • サブクラスの判定のswitch文が巨大になってきたとき

解決したらどうなるか

  • switch文を無くすことができる

どう解決しているのか

  • 各サブクラスのクラス名を動的に取得し、そのメソッドを動的に実行する
  • こうすることで、switch文を消せる

@at-grandpa
Copy link
Owner Author

Factory Method パターン

  • メソッドを使ってオブジェクトを生成すれば、生成に柔軟性が生まれる
  • 柔軟性が必要なときだけにしておく

どんな問題を解決するのか

  • オブジェクトの生成に関して、「生成オブジェクトの切り分け」「多少の前準備が必要」などの柔軟性が欲しい場合

解決したらどうなるか

  • メソッド経由で生成するので、そのメソッド以降の使用者側には、オブジェクト生成に関する知識は不要になる

どう解決しているのか

  • 結合度が下がる
    • メソッドを使用している側は、オブジェクトを変更してもなんら変わらない

@at-grandpa
Copy link
Owner Author

at-grandpa commented Jan 11, 2018

imposter パターン

  • 処理にバリエーションを持たせたい
    • どういうことだ
    • 既存オブジェクトと同じプロトコルを備えて、実装は異なる新たなオブジェクトを作る
      • やっぱりインターフェースなんだよなー
  • 普通はどうするか
    • 手続き型で書かれたコードにバリエーションは?
      • 条件分岐を導入する
      • これは増殖する
      • ポリモーフィズムを導入すれば重複したコードを健全に保てる
        • これは pluggable object パターンだな
  • 既存の構造があり、既にオブジェクトもあるような状況を考える
    • この状態で、システムに新たな仕事をさせなければならない
    • 複数のメソッドを変更しなければならない
    • TDDでは、二つの局面に起きる
      • テストを書いていて、新しいシナリオを追加しないとだめだけど、それができない
        • インターフェースを一致させておけば、入れ替えるだけでok
        • 異なるものが同一に扱えると気づく
  • imposterはちょっと大きな話しだなぁ
    • 結局はインターフェースを共通にして同じように振る舞う、に限る
    • Null Object パターンもそうだった
    • Compositeもそうだ
  • 重複排除に一躍買う

どんな問題を解決するのか

  • あたらしい処理のバリエーションを追加したい

解決したらどうなるか

  • 修正範囲が少なく、重複が少なく、機能を追加できる

どう解決しているのか

  • インターフェースを統一させて、処理の共通化を実現している

@at-grandpa
Copy link
Owner Author

at-grandpa commented Jan 12, 2018

Composite パターン

  • 複数のオブジェクトたちの振る舞いを組み合わせた振る舞いを持つオブジェクトを実装するには?
    • 構成要素をまとめたimposterを作る
  • 単一オブジェクトについてのコードと、複数のオブジェクトについてのコードでは、重複が起きる!!
    • この重複は課題だ
  • 単一オブジェクトと複数オブジェクトで同じ意味をもつものは、同じプロトコルにする
    • こうすることで、OverAllHogeなどのクラスを作らなくて済む
  • 問題もある
    • プログラマのトリックであって、プログラマ以外の人には理解されない
  • ポイント
    • 重複が発生してからCompositeを導入すればよい

どんな問題を解決するのか

  • 単一オブジェクトと複数オブジェクトの間で重複が発生している問題

解決したらどうなるか

  • 単一オブジェクトと複数オブジェクトの間で重複が解消されて、コードが綺麗になる

どう解決しているのか

  • 単一オブジェクトと複数オブジェクトの間で同じプロトコルを持たせる

@at-grandpa
Copy link
Owner Author

at-grandpa commented Jan 12, 2018

Collecting Parameter パターン

  • たくさんのオブジェクトたちの処理結果を集めたい
    • 処理のパラメータに結果格納用のオブジェクトを渡す
      • 共通のインターフェースにしやすいね
      • TestSuiteのTestResultみたいなやつ
  • 収集した情報を加工したくなったときとかも便利

どんな問題を解決するのか

  • 複数のオブジェクトの処理結果をうまく加工したい

解決したらどうなるか

  • 処理結果がオブジェクトになっているので、その中で加工すればよい

どう解決しているのか

  • 処理結果を集めるオブジェクトを各処理に集めて、それをそのオブジェクトの中で加工すれば良い

@at-grandpa
Copy link
Owner Author

Singleton パターン

  • グローバル変数の無いプログラミング言語でグローバル変数を作るにはどうするか
    • 決してやってはいけない

@at-grandpa
Copy link
Owner Author

この章で得た知見

  • 各パターンはどういう問題を解決しているかがわかった
  • このテンプレートに従って埋めていくと、良いね
    • あとはこの流れで、実際にコードを書いていく
      • 問題のコードを書き、実際のデザパタで問題を解決する

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant