CompositeパターンとCommandパターンの事例
汎用的なデザインパターンフレームワークを実現する
前回(第3回:http://thinkit.jp/article/933/1/)はAdapterパターンとFactory Methodパターンの事例を紹介しました。
Adapterパターンは、既存クラスのインターフェースを変えることなく、利用者が望む別のインターフェースに変換して利用するパターンです。既存クラスをそのまま利用した場合、別のクラスに変更しようとすると大幅な修正が必要になりますが、Adapterパターンでラップして利用することで最小限の修正で済ますことができます。
一方、Factory Methodパターンはインスタンスを生成する仕組みとインスタンスを決定する仕組みを分けるパターンです。生成するインスタンスを後から決めたり、変更したりする場合に有効です。
今回はChain of Responsibilityパターンの汎用的なフレームワークであるcommons chain 1.2(http://commons.apache.org/chain/)を事例に、CompositeパターンとCommandパターン、そしてChain of Responsibilityパターンを取り上げます。これらはGoFのデザインパターンです。
Compositeパターン(図1-1)は構造に分類されるパターンです。Compositeとは「複合物」や「混合物」という意味です。Composite役は「器」であり、Leaf役はその器の「中身」です。そして「器」には別の「器」も入れることができます。Compositeパターンはツリー構造のような再帰的な構造を実現できます。また、このパターンで実現した構造内にあるすべてのオブジェクトに対して、Client役は違いを意識することなくComponent役で定義した操作を行うことができます。
ファイルシステムを例にすると、Composite役はフォルダになり、Leaf役はファイルになります。フォルダにはファイルや別のフォルダを入れることができます。またComponent役の持つメソッドは、フォルダとファイルに共通する「コピー」「貼り付け」「削除」などの操作になります。ファイルシステムは、フォルダやファイルの違いを意識することなく、それらの操作が行えます。
Commandパターン(図1-2)はふるまいに分類されるパターンです。Commandとは「命令」という意味です。
通常、オブジェクトに対して何かの操作をするときには、メソッドを呼び出します。呼び出した結果はオブジェクトに反映されますが、メソッドを呼び出した履歴は残りません。このパターンはReceiver役の「メソッドの呼び出し」を命令クラス(ConcreteCommand役)としてカプセル化します。命令クラスは共通API(Command役)のexecuteメソッドを実装します。そのメソッドではReceiver役の「メソッドの呼び出し」を行います。「メソッドの呼び出し」を命令クラスのインスタンスで表すことで実行した命令の履歴を残すことができます。
また、例えば写真の撮影において「3秒待つ」命令や「カメラのシャッターを押す」命令がある場合、それらの命令のインスタンスをあらかじめ生成しておき、まとめて実行することで「オート撮影」命令を疑似的に作り出すことができます。Commandパターンはこのように命令のインスタンスを組み合わせて新しい命令を作り出すこともできるのです。
commons chainで実現するChain of Responsibilityパターンとは?
Chain of Responsibilityパターン(図1-3)はふるまいに分類されるパターンです。
Chain of Responsibilityは「責務の連鎖」という意味になります。責務とは「自分の責任として果たさねばならない事柄」のことであり、このパターンではConcreteHandler役がその責務を持っています。
ConcreteHandler役の責務はClient役から要求があった場合、自分が果たす「要求に対する処理」を行うことです。一方、Handler役はConcreteHandler役に要求を出すための共通のAPIを定めます。またHandler役は自身を鎖状につなぐ「チェーン構造」になっています。
このパターンは、それぞれの「要求に対する処理」を持つConcreteHandler役を鎖状につなぎ、「チェーン構造」にすることで1つの処理を形成します。Client役はその「チェーン構造」の処理に要求を出すことで、最終的に要求を満たします。
例えば図1-4のような献血のサービスがあるとします。そのサービスでは血液型ごとに採血する担当者(ConcreteHandler役)が割り当てられています。O型の人(Client役)が採血を依頼した場合、O型の人を採血する担当者になるまで次々と採血担当者を渡り歩き、最終的に献血という要求を満たします。
今回はcommons chainの中で、CompositeパターンとCommandパターンがどのように適用されているのか、どのような効果があるのかを分析して理解を深めていきましょう。