GRASP
GRASPとは、General Responsibility Assignment Software PatternあるいはPrinciple(汎用的責任性割り当てパターン/原則)の頭字語であり、オブジェクト指向設計に向けた九つの原則セットまたはパターンセットである。計算機科学者クレーグ・ラーマンの1997年著作「実践UMLパターン -Applying UML and Patterns-」で初めて紹介されている。
「ソフトウェア開発において決定的な設計ツールになるのは、設計の原則の中で磨き上げられたメンタルであって、UMLやその他のテクノロジーではない」がラーマンの主張であり、GRASPとはオブジェクト指向開発を助けるためのメンタルツール(mental tool)であると定義している。
質問:オブジェクトに責務を割り当てる原則とは何か?
回答:その責務を全うするのに必要な情報を持つクラスに割り当てるべきである。
このパターンは、オブジェクトに責務を割り当てる際の一般的な原則である。情報エキスパートパターンは、情報のエキスパート、すなわち必要な情報を全て持っているクラスに責務を割り当てるべきとする。この原則は、ソフトウェアシステムにおいての責務と演算を集中させない(Big ball of mudとは対照的である)。責務と意思決定の分散が進むと情報の隠蔽化が促進され、他のクラスと情報エキスパートクラスの実装との結合の度合いが小さくなる。情報エキスパートパターンを適切に使いこなしたシステムは理解しやすく、維持・拡張が簡単で、また将来の開発で再利用できる可能性が高まる。マーティン・ファウラーは、Web の記事 「GetterEradicator」でラーマンの情報エキスパートを参照している。
質問:クラスはどのようなプロパティとメソッドで構成されるべきか?
回答:一つの責務を全うするのに必要最低限かつ、その責務に特化しているプロパティとメソッドのみで構成されるべきである。
このパターンは、オブジェクトが適切に責務を集中させており、管理・理解が可能な状態を保つための尺度である。高凝集性とは、ある要素の責務が強く関連しており、またその要素に集中していることを意味する。クラスやサブシステムにプログラムを分解するのは、システムの凝集性を高める活動の例だと言える。逆に凝集性が低いということは、関連のない責務を持ちすぎている場合である。凝集性が低い要素は理解が難しく、再利用・維持管理が困難で、変更も行いづらい。
質問:クラス間の関連性と依存性はどのように定義されるべきか?
回答:可能な限り小さくするべきである。関連性を少なくするとは各クラスの公開メンバを少なくすることである。依存性を少なくするとは公開クラスを少なくすることであり、その具体策としては特定のインターフェースに公開クラス情報を集中させることである。
質問:誰がオブジェクトAを生成するべきか?
回答:Aのコンポジション先になる者、Aのアグリゲーション先になる者、Aの生成を記録していく者、Aを密接に使用する者、Aの生成に必要な情報を持つ者などである。
このパターンは、クラスの新しいインスタンスを作成することに責任を持つのは誰かという問題を解決する。オブジェクトの作成は、オブジェクト指向のシステムではあらゆるところで行われる活動であるから、生成者パターンは重要である。生成者パターンを有効に用いるシステムは、疎結合性が高くなり、理解のしやすさ、カプセル化が促進され、オブジェクトが今後再利用できる可能性が増加する。たとえば、二つのクラスA,Bがあったとき、B が A を包含する、A を合成・集約する、A を密接に使用する、A の初期化情報を持っているといった場合、クラス B がクラス A の作成に責任を持つべきであり、B は A の生成者として自然なオブジェクトと言える。Factoryパターンは、複雑なオブジェクト作成ロジックなど、特別な検討が必要な場合に、「生成者」の替わりになる方法である。この方法では、Factoryと呼ばれる「純粋な人工的」(後述)であるオブジェクトを作ってオブジェクトの作成を行わせることで目的を達する。
質問:誰が入力システム・イベントを扱う責務を持つべきか?
回答:該当システムをカバーするコントローラが、該当システムで発生する全入力イベントを扱うべきである。
このパターンは、システム全体やユースケースシナリオを表現するユーザインタフェースでないクラスにシステムイベントを扱う責務を割り当てる。ユースケースのコントローラはユースケースの全てのシステムイベントを扱い、複数のユースケースで使用できる(例えば、「ユーザーの作成」「ユーザーの削除」というユースケースで、それぞれUserControllerオブジェクトを持たずに一つのオブジェクトを共有してよい)。コントローラは、UI層以上にあって、システムに対する操作を受け取り調整する(制御する)最初のオブジェクトとして定義される。コントローラは、他のオブジェクトに必要な作業の実施を委譲する。他のオブジェクトの活動を制御し、連携させる。一般的なレイヤ構造を持ったオブジェクト指向のシステムでは、GRASP コントローラはアプリケーションやサービス層の一部と考えられる (アプリケーション層/サービス層、ドメイン層を明確に区別している場合)。
質問:どういったオブジェクトに責務を割り当てると、オブジェクトたちの密結合を回避できるのか?どのようにオブジェクトを切り離せば、リユーザブルな疎結合を実現できるのか?
回答:オブジェクト同士が直接つながらないように、コンポーネントまたはサービスを仲介する中間オブジェクトを用意して、それに責務を割り当てるべきである。
このパターンは、二つの要素の中間にオブジェクトを設け両者の仲介を行う責務を割り当てることで、二つの要素間の疎結合性(および再利用の可能性)を促進する。Model View Controllerにおいてコントローラがデータ(モデル)と表現(ビュー)の仲介を行うのはその一例と言える。
質問:どのように型のすげ替え部分を扱うべきか?どのようにすげ替え可能なコンポーネントを作るべきか?
回答:型別の動作のすげ替えならば、同じ動作名義に対してオブジェクト別の異なる動作内容を結合できるポリモーフィックな型を用意するべきである。
このパターンは、型に基づいて振る舞いの変動部分を定義する責務を、変動が起きる型に割り当てる。これは、ポリモルフィックな操作を持たせることで実現できる。
質問:構成の変化を前提にしたオブジェクトたちが、自身の変化による他者への影響波及を回避するには、どのようにオブジェクトを設計するべきか?
回答:オブジェクトの変化する構成の箇所を特定した上で、その箇所をカバーするための不変構成のインターフェースを用意するべきである。
このパターンは、周辺の要素(オブジェクト、システム、サブシステム)の変動から注目する要素を保護するために、不安定な部分をインタフェースを用いて収束させ、ポリモーフィズムを用いてインターフェイスを実装させる。
質問:専門領域オブジェクトをサポートする、専門領域から離れた純粋な機能実体とはあり得るのか?
回答:オブジェクトに自由に分離結合できる、特定機能の凝集体を操作するためのインターフェースがそうである。
このパターンは、問題領域に登場する概念を表すクラスではなく、疎結合や、高凝集性、それらから得られる再利用可能性を実現するために作られるクラスである(情報エキスパートで実現できない場合)。この種類のクラスはドメイン駆動設計ではサービスと呼ばれる。