📝デザインパターン

📝デザインパターン

GoF デザインパターン.

ref. デザインパターン (ソフトウェア) - Wikipedia

パターンとは #

建築環境に繰り返し現れる課題を解決に導く具体的な方策を記述したもの.

アレクサンダーのパターン形式 #

  • パターン名
  • 写真
  • 上位パターンへのつながり
  • 本文
  • 下位パターンへのつながり

パターンランゲージ #

建築において繰り返し現れる構造を再利用しやすい形式でまとめたもの. あるいは, パターンを集めて一つの体系としてまとぬあげたもの.

建築家クリストファーアレクサンダーが考えた建築手法.

時を超える建築の道 #

パターンランゲージを記した建築理論. 本の題名.

角谷信太郎さんのおもしろいはなしの youtube 動画も見つけた.

無名の質 #

生き生きとした建築や街が備えている特性. 古い街並みに潜む住みやすさや美しさ.

生成に関するデザインパターン #

Factoryの原則.

生成と実装を分離することで, プログラムはシンプルになる.

  • 生成パラメータの指定方法をシンプルに
  • 生成後の管理をシンプルに
  • 生成するオブジェクトの指定方法をシンプルに

特定のケースで特定のオブジェクトを生成するのは手続き思考的.

2 つをわけて考えることで設計に集中.

  • 動作方法
  • 生成,管理方法

Factory Method #

オブジェクトの生成を行う時のインタフェースを規定して, インスタンス化するクラスを決定するのはサブクラスに任せる.

factoryMethod の中でオブジェクトの生成をすることで, 生成を生成オブジェクト (メソッド) 内にカプセル化.

switch 文は Abstract Factory によってリファクタリング可能.

C 言語での応用 #

C 言語で Abstruct Data Type な設計をつかうときの常套手段.

int createInstance (void) {
  return calloc (4);
}

int destroyInstance (int ptr) {
  free (ptr);
  return NULL;
}

int main (void) {
  int *instance = createInstance ();
  instance = destoryInstance (instance);
  return 0;
}

グループ化されたオブジェクトについて,

  • 生成用オブジェクト (Creator)
  • 振る舞い用オブジェクト (Product)

のペアを作成するとき.

Abstract Factory #

関連するオブジェクト群をその具象クラスを明確にせずに生成するための インタフェースを提供する.

関連するインスタンス群を生成するための API を集約することによって, 複数のモジュール群の再利用を効率化することを目的とする.

実装は意識せずに, インタフェース (API) のみで, 抽象的な部品をつくりあげる.

Factory Method 自体のカプセル化. Factory Methodの進化版. マルチ Factory Method. Factory Methods.

視点をかえると Factory MethodBuilder Pattern とも言える.

Builder Pattern #

オブジェクトの生成手順が複雑な場合に, その生成過程をカプセル化する.

ドメイン駆動設計でいうところのエンティティオブジェクトを生成する Factory.

Prototype #

生成するオブジェクトの原型をコピーして新しいオブジェクトを生成する.

Abstract Factory と似ている.

  • new でオブジェクトを生成すれば Abstract Factory.
  • clone をつかう場合の Prototype.

複製を作成するためのメソッドを用意する. といういたって単純なもの.

プロトタイプ が複製を担当し, それ以外の生成における操作をクライアントが 担っている.

Map にテンプレートを登録しておいて, 利用するときに複製する. バイナリデータをマップにいれておいて, キーとなる名前をつけて管理する, など.

Java には, Clonable インタフェースがある.

クラスの数をかなり減らすことができる.


Abstract Factory パターンでなされるように, クライアント・アプリケーションにおいてオブジェクトの生成者をサブクラスにすることを回避する.

標準的な方法 (例えば’new') で新しいオブジェクトを作ることによる固有のコストが所与のアプリケーションにとって高すぎる時にそれを回避する.

Singleton #

システム内で生成可能なインスタンス数をひとつだけに制限する.

一般的なシングルトンパターンの実装方法は以下.

  • static method
  • private な 定数に オブジェクトを保存
  • オブジェクトは getInstance () メソッドで取得

各 Factory の違い #

デザインはしばしば,

  • 比較的に複雑でなく,
  • カスタマイズしやすく,
  • サブクラスを急速に増やす

ファクトリメソッドを用いるところから出発

一層の柔軟性が必要となる箇所が発見されるに伴い,より柔軟だが複雑Abstract Factory, Prototype, Builder へと発達してゆく.

Factory Method #

ファクトリのクライアントとなるオブジェクトが, ファクトリオブジェクトにインスタンスの生成を委譲する.

  • 親クラスである Creator クラスが子クラスである ConcreteCreator クラスにオブジェクトの生成を委ねる.
  • Creator クラスと ConcreteCreator クラスとの関連である.
  • 継承
  • [オブジェクト生成] の抽象化にポイントを置いたパターン

Abstract Factory #

親クラスであるファクトリが, 実際のオブジェクトの生成をサブクラスに委譲する.

  • Client のインスタンスが ConcreteFactory のインスタンスにオブジェクトの生成を委ねる
  • オブジェクト同士の関連
  • 委譲
  • [関連するオブジェクト群をまとめて生成するための手順] の抽象化

References #

構造に関するパターン #

Adapter Pattern #

インタフェースを変換することによりインタフェースに互換性がない クラス同士を接続する.

単なるラッパークラスとも言える.

ラッパー方法は 2 つ.

  • 継承でラッパーする.
  • 委譲でラッパーする.

ref. Adapter, Facade, Proxy パターンの違いのメモ | Futurismo

ここでは, ConcurrentLinkedQueue と ConcurrentArrayQueue を生成時に交換するために, Adapter をつかっている.

ref. Java で Producer-Consumer Pattern を実装してみた | Futurismo

Bridge Pattern #

クライアントがアクセスするクラス (インタフェース) と実装クラスを分離して, それぞれを独立に変更できるようにする.

オブジェクト指向のこころの本にとても詳しく書いてある. これぞ, オブジェクト指向の本質! みたいな. インタフェースを用いて設計 する.

機能追加と機能実装の組み合わせ爆発を抑止することができる.

Composite Pattern #

部分-全体階層を表現するために, クラスの木構造に組み立てる.

同一のクラスから派生したサブクラスを木構造のノードとし, クライアントは木構造の任意の部分を同一のインタフェースで扱える.

同一クラス というところがポイント. 親子の関係で表現できればいい. Parent-Childというキーワードもポイント. 別名, フォルダパターン. フォルダにはフォルダとファイルがある. こっちの名前のがわかりやすいし, 覚えやすい.

Decorator #

サブクラス化ではなく委譲により, クラスに新しい機能を追加する.

ポイントは, オブジェクトの委譲方法が,

  • 集約ではなくてコンポジション
  • 継承ではなくてコンポジション

LinkedList 構造.

ref. 動的に機能追加!Java で Decolator パターンを実装してみた | Futurismo

Facade #

複数のクラス群からなるサブシステムにアクセスするためのインタフェースを提供する. facade とは, 正面という意味.

Proxy Pattern #

オブジェクトへのアクセスをフックするための代理オブジェクトを提供する. Proxy は英語で代理人.

本物のオブジェクトにアクセスするまえにクッションを置くことで, そこに機能追加できる.代理プラスアルファの機能をもつ.

  • ログ
  • トレース
  • キャッシュ
  • モック

ref. Adapter, Facade, Proxy パターンの違いのメモ | Futurismo

Flyweight Pattern #

一度生成したインスタンスはプーリングしておき必要なときに取り出して使う.

リソースコスト削減のためのキャッシュといってもいい.

シングルトンパターンは フライウェイトパターンと合わせて利用されることがおおい. 特徴は,

  • private な 変数に オブジェクトを保存.
  • オブジェクトが存在すれば, getInstance で渡す.
  • オブジェクトが存在しなければオブジェクトを作成して getInstance で渡す.

wikipedia から説明引用

その時点で対象のインスタンスが生成されていない場合

  • 対象のインスタンスを新たに生成する.
  • 生成したインスタンスをプールする (言い換えると, メンバのコンテナオブジェクトに格納する).
  • 成されたインスタンスを返す.

対象のインスタンスが既に生成されていた場合

  • 対象のインスタンスをプールから呼び出す.
  • 対象のインスタンスを返す.

振る舞いに関するデザインパターン #

Command Pattern #

動作を表現するオブジェクト.

動作とそれに伴うパラメータをカプセル化したもの.

特徴 #

  • 手続きに必要なパラメータの一時格納場所として便利.
  • 関数呼び出しのためのパラメータを集めて, 後で使用するためにコマンドを保存しておくことができる.
  • 保存されたデータ構造に対する追加, 削除が可能になる.
  • コマンドの生成と実行のタイミングの分離.

Chain of Responsibility #

責務を持たせたオブジェクトの Chain に 要求を渡していく.

要求は,

  • そのオブジェクトで処理できればそこで処理する
  • そのオブジェクトで処理できなければ, 次のオブジェクトに渡す.

参考記事: #

Interpreter #

文字列からなる構文を構文解析 (Interprete) し, 構文を表現したオブジェクト構造ともとの文字列を関連付ける.

Iterator Pattern #

オブジェクトの集合 (データ構造, コンテナ) があるとき, その集合の内部構造はカプセル化したままで, 要素に対して順にアクセスする方法を提供する.

コンテナオブジェクトの要素を列挙する手段を独立させることによって, コンテナの内部仕様に依存しない反復子を提供することを目的とする.

言語でサポートしていることがおおい. 拡張 for 文, for-each 文などと呼ばれる.

自前で実装するよりも, 言語に頼るほうがよい.

Java #

Collection フレームワークでは, 反復子が利用できる.

     List<Integer> list = LinkedList<Integer>
     for (int i; list) {
     System.out.println (i);
     }

Iterator インタフェースを実装することで, 自前のクラスにイテレータを適用できる.

Ruby #

Enumerable モジュールを Mix-in する.

参考: #

Mediator #

複数のオブジェクトを相互作用させる場合に, お互いのオブジェクト同士が直接参照することをなくすため, 相互作用そのものをオブジェクトとして定義する.

Memento #

オブジェクトの状態を保存しておき, 元に戻せるようにしておく. オブジェクトを以前の状態に (ロールバックにより) 戻す能力を提供する.

Observer #

あるオブジェクトに依存した複数のオブジェクトがある場合に, 被依存オブジェクトの状態変化を, 依存オブジェクトに通知する.

Ruby ではライブラリがある.

イベントリスナ.

State #

状態に応じてオブジェクトの振る舞いを変更したいときに, 振る舞いを別オブジェクトにカプセル化する.

ストラテジパターン | Strategy Pattern #

アルゴリズムをカプセル化して, アルゴリズムを交換可能にする. ひとつの入力データに対して, アルゴリズム毎に異なる結果を出力する.

アプリケーションで使用されるアルゴリズムを動的に切り替える必要がある際に有用.

  • Android
  • Windows
  • Linux

名前のつけかたはxxxStrategyが多い.

変更を考慮して設計するアプローチ #

オブジェクト思考のこころより引用.

  • 変更内容を予測するのではなくて, どこに変更が発生するのかを予測する
  • 実装を用いてプログラミングするのではなくて, インタフェースを用いてプログラミングする.
    • クラス継承よりも, オブジェクトの集約を多用する.
    • 流動的要素をカプセル化する.

switch 文を多用したり, グチャグチャになってきたら赤信号. switch 文は流動的要素なので, その部分をクラスに分離してカプセル化する.

クラスに分離する際は, 継承をさけて集約を多用する.

Effective Java から #

p101 戦略を表現するために関数オブジェクトを使用する

  • 戦略を現すインタフェースを用意
  • 個々の具象戦略に関してそのインタフェースを実装しているクラスを定義.
    • 具象戦略が一度しか利用されないならば, 無名クラスで作成
    • 繰り返し利用されるならば, public static final の フィールド or static factory method を通じて提供.

Template Method #

単なる継承.

アルゴリズムを複数のステップに分解し, それぞれのステップを抽象メソッドにする. 各ステップでのメソッドの実装はサブクラスで定義する.

システムのフレームワークを構築するための手段としてよく活用される.

Factory Method パターンは, 内部に Template Method パターンを包含することが多い

class A
  def execute ()
    raise "to be implemented"
  end
end

class B < A
  def execute ()
  end
end

class C < A
  def execute ()
  end
end

Visitor Pattern #

複数のオブジェクトからなるオブジェクト構造があるときに, それぞれのオブジェクト要素に処理を追加またはオブジェクト要素の処理を変更するため, Visitor クラスを用意する.

デザインパターン深堀り #

カプセル化の視点で整理 #

カプセル化がデータ隠蔽というのは狭義の定義.

カプセル化とはあらゆるものを隠蔽すること.

  • データ
  • メソッド
  • 実装
  • 派生クラス
  • 設計の詳細
  • 実体化の規則

流動的要素を探し出してカプセル化する. 委譲は手段.

この観点から, デザインパターンをとらえ直すと,

流動的要素 Pattern
アルゴリズム Strategy
状態 State
振る舞い Decorator
パターンマッチ, 型 Visitor
動作, 要求 Command
実装 Bridge
変化への反応 Observer
相互作用 Mediator
生成 Factory Method, Abstract Factory , Prototype
一意性 Singleton, Flyweight
構造の生成 Builder
集合の巡回構造 Iterator
インタフェース Adapter
システム Facade
設計の詳細 Template Method

パターンで考える #

オブジェクト指向のこころ 13 章より.

  • パターンの洗い出し … ドメインに存在するパターンをまずは列挙.
  • パターンの分析・適用 … 1-4 を繰り返す.
    1. パターンの並べ替え
    2. パターンの選択と設計の拡張
    3. 追加のパターンの洗い出し
    4. 繰り返し
  • 設計の詳細

関数型言語との関係 #

References #

概要がかかれたページ

噛み砕かれた, わかりやすい説明.

図解で解説されている.

サンプルソースが豊富.

Gang Of Four のインタビュー

結城浩さんの並列・平行プログラミングのパターン紹介


Tags