デザインパターン (ソフトウェア)

ソフトウェア開発におけるデザインパターンまたは設計パターン: design pattern)とは、過去のソフトウェア設計者が発見し編み出した設計ノウハウを蓄積し、名前をつけ、再利用しやすいように特定の規約に従ってカタログ化したものである。パターン(pattern)とは、型紙(かたがみ)やひな形を意味する。

本稿でのデザインは狭義の設計という意味であり、CSSHTMLなどで使われる意匠デザインの定形を示す「デザインパターン」とは異なる。

概要

書籍『オブジェクト指向における再利用のためのデザインパターン』において、GoF (Gang of Four) と呼ばれる4人の共著者は、デザインパターンという用語を初めてソフトウェア開発に導入した。GoFは、エーリヒ・ガンマリチャード・ヘルムラルフ・ジョンソンジョン・ブリシディースの4人である。彼らは、その書籍の中で23種類のパターンを取り上げた。

彼らはこう述べている。

[Design patterns] solve specific design problems and make object-oriented designs more flexible, elegant, and ultimately reusable. They help designers reuse successful designs by basing new designs on prior experience. A designer who is familiar with such patterns can apply them immediately to design problems without having to rediscover them.

コンピュータプログラミングで、素人と達人の間では驚くほどの生産性の差があり、その差はかなりの部分が経験の違いからきている。達人は、さまざまな難局を、何度も何度も耐え忍んで乗り切ってきている。そのような達人たちが同じ問題に取り組んだ場合、典型的にはみな同じパターンの解決策に辿り着く。これがデザインパターンである (GoF)。

それぞれのパターンは、プログラマの間で何度も繰り返し考え出されてきた。したがって、それは最善の解決策ではないかもしれないが、その種の問題に対するトレードオフを考慮した、典型的な解決策ではある。さらに、コストがかかるかもしれない問題解決を実際に行う前の先行調査として、大変役に立つ。パターンに名前が付いていることが重要である。なぜなら、名前が付いていることで問題や解決策を記述したり、会話の中で取り上げたりすることができるようになるからである。

主要なデザインパターンの一覧

生成に関するパターン

パターン名 概要 GoF Code Complete[1]
Abstract Factory 関連する一連のインスタンスを状況に応じて、適切に生成する方法を提供する。 Yes Yes
Builder 複合化されたインスタンスの生成過程を隠蔽する。 Yes No
Factory Method 実際に生成されるインスタンスに依存しない、インスタンスの生成方法を提供する。 Yes Yes
Prototype 同様のインスタンスを生成するために、原型のインスタンスを複製する。 Yes No
Singleton あるクラスについて、インスタンスが単一であることを保証する。 Yes Yes

構造に関するパターン

パターン名 概要 GoF Code Complete[1]
Adapter 元々関連性のない2つのクラスを接続するクラスを作る。 Yes Yes
Bridge クラスなどの実装と、呼び出し側の間の橋渡しをするクラスを用意し、実装を隠蔽する。 Yes Yes
Composite 再帰的な構造を表現する。 Yes Yes
Decorator あるインスタンスに対し、動的に付加機能を追加する。Filterとも呼ばれる。 Yes Yes
Facade 複数のサブシステムの窓口となる共通のインタフェースを提供する。 Yes Yes
Flyweight 多数のインスタンスを共有し、インスタンスの構築のための負荷を減らす。 Yes No
Proxy 共通のインタフェースを持つインスタンスを内包し、利用者からのアクセスを代理する。Wrapperとも呼ばれる。 Yes No

振る舞いに関するパターン

パターン名 概要 GoF Code Complete[1]
Chain of Responsibility イベントの送受信を行う複数のオブジェクトを鎖状につなぎ、それらの間をイベントが渡されていくようにする。 Yes No
Command 複数の異なる操作について、それぞれに対応するオブジェクトを用意し、オブジェクトを切り替えることで、操作の切り替えを実現する。 Yes No
Interpreter 構文解析のために、文法規則を反映するクラス構造を作る。 Yes No
Iterator 複数の要素を内包するオブジェクトのすべての要素に対して、順番にアクセスする方法を提供する。反復子 Yes Yes
Mediator オブジェクト間の相互作用を仲介するオブジェクトを定義し、オブジェクト間の結合度を低くする。 Yes No
Memento データ構造に対する一連の操作のそれぞれを記録しておき、以前の状態の復帰または操作の再現が行えるようにする。 Yes No
Observer (出版-購読型モデル) インスタンスの変化を他のインスタンスから監視できるようにする。Listenerとも呼ばれる。 Yes Yes
State オブジェクトの状態を変化させることで、処理内容を変えられるようにする。 Yes No
Strategy データ構造に対して適用する一連のアルゴリズムカプセル化し、アルゴリズムの切り替えを容易にする。 Yes Yes
Template Method あるアルゴリズムの途中経過で必要な処理を抽象メソッドに委ね、その実装を変えることで処理内容を変えられるようにする。 Yes Yes
Visitor データ構造を保持するクラスと、それに対して処理を行うクラスを分離する。 Yes No

マルチスレッドプログラミングに関するパターン

ソフトウェアに並行性並列性を導入するためのマルチスレッドプログラミングは、難易度が比較的高いとされる。そのため、よく現れる問題に対して、汎用的に使用できる種々のパターンが考案されている。後発の高水準プログラミング言語や、並行・並列プログラミングのサポートを重視した言語では、標準ライブラリや言語構文・言語仕様に取り込まれているものも多い。

パターン名 概要
Active object英語版 (Actor) メソッドの呼び出しとメソッドの実際の実行を分離することで、並行性を導入する。各オブジェクトは、利用者からの要求を管理するためのメッセージキュースケジューラを持つ。
Balking英語版 前提条件が満たされていない場合は、(その時点での)処理の実行をあきらめる。
Double-checked locking英語版 ロックの取得におけるオーバヘッドを削減するための技法。まずスレッドセーフでない方法で「ロックヒント」を調べて、それが成功したら実際のロックを試みる。
Future 「処理が完了しているかどうか分からない処理結果」を表すオブジェクトを作成することで同期を実現する。処理が完了していないうちに結果を取得しようとした場合は、処理が完了するまでロックされる。
Guarded suspension英語版 前提条件が満たされるまで待機するための機構。
Lock リソースに対して1つのスレッドが「ロック」をかけて、その間は他のスレッドがそのリソースにアクセスしたり変更を加えたりできないようにする。[2]
Monitor 排他的に実行しなければならないメソッド群を持つオブジェクトをスレッドセーフに利用できるようにするための機構。Javaは、これを言語レベルでサポートしている。
Producer-consumer 「生産者」 (producer) スレッド群がデータを生成して「通信路」に追加し、「消費者」 (consumer) スレッド群がそのデータを「通信路」から取り出して処理するという構造。必要な同期はすべて「通信路」によって行なわれるため、生産者と消費者のルーチンは同期を意識せずに実装できる。この通信路は、同期キューなどで実現される(一部の言語はこれを標準ライブラリで提供している)。
Reactor英語版 同期的に扱わなければならないリソース群に対する非同期的インタフェースを提供する。
Readers–writer lock英語版 書き込みは排他アクセスが必要だが、読み込みは並行に行えるようにしたい場合のためのロック機構。
Scheduler英語版 シングルスレッドで実行される処理(例えばファイルへの書き込み)の実行を各スレッドに許可するタイミングを明確に制御する。
Thread pool英語版 多数のスレッドを作成して、それらに多数のタスクを処理させる。典型的な状況ではスレッド数よりもかなり多くのタスクが存在し、各スレッドは、あるタスクの処理が終わると次の処理待ちタスクの実行に取りかかる。一般に、Producer-consumerパターンを使って実現される。
Thread-specific storage 静的変数・グローバル変数のように扱えるがスレッドごとに異なる内容を格納できるメモリ領域を提供する。
Two-phase termination スレッドを安全に終了させる方法。スレッドは、終了要求を表すフラグを定期的に確認して、それがセットされたら終了処理を行う。

注意および批判

デザインパターンは、よく使われる設計を一般化された形でまとめたものに過ぎない。そのため、具体的な実装を提供するものではなく、あくまでもコンセプトとして参照されることが意図されている。つまり、サンプルコードは、実装例に過ぎない。

デザインパターンは、すべての状況における最善の設計ではない。『Code Complete』は、デザインパターンを紹介している書籍の1つであるが、デザインパターンをむやみに適用するのは不適切であり、不適切な使用はコードの複雑さを無意味に高めてしまうと注意している[1]

一部のデザインパターンは、プログラミング言語(例: Java, C++)の機能の欠損の印であると主張されることがある。計算機科学者のピーター・ノーヴィグは、GoFによるデザインパターン本の23パターンのうち16パターンは、言語によるサポートによって単純化または除去できることをLispDylanを用いて実演した[3]

脚注

  1. ^ a b c d McConnell, Steve (June 2004). “Design in Construction”. Code Complete (2nd ed.). Microsoft Press. p. 104. ISBN 978-0-7356-1967-8. "Table 5.1 Popular Design Patterns" 
  2. ^ Lock Pattern
  3. ^ Norvig, Peter (1998). Design Patterns in Dynamic Languages.

参考文献

関連項目