ホーム < ゲームつくろー! < デザインパターン習得編
Chain of Responsibility
〜実行する人を自動選択
@ いわゆる「たらいまわし」
Chain of Responsibilityパターンは「責任の鎖」、すなわちクライアントの「○○して欲しい」という要求に答える人が次々にその要求を伝えて行き、適任者がその要求をかなえるという「たらいまわし」の振る舞いを実現するものです。
このパターンは親クラスおよびその派生クラスが共通の「窓口関数」を持っていて、その窓口伝いに要求が連鎖していく構造になっています。窓口の鎖に誰がいるかが分からなくても良いというのがポイントです。
ゲーム製作でChain of Responsibilityパターンを適用出来るところといえば、正直なかなか見つからないのですが、switch〜caseが連なるところなどはこのパターンに置き換えられることがあります。Factory Methodパターンなどで活用できるかもしれません。
通常、Factoryクラスに新しいキャラクタの生成機構を追加するときには、派生が行われます。しかし、Chain of Responsibilityパターンを使うと、任意のキャラクタのFactoryオブジェクトを追加できるようになります。
WeaponFactoryオブジェクトにShieldFactoryオブジェクトを登録し、ShieldFactoryオブジェクトにSwordFactoryオブジェクトを登録して、
Item* LongSword = WeaponFactory->GetObject(ID_LONGSWORD);
とすると、まずWeaponFactory::GetObject関数内で指定のID_LONGSWORDに一致するクラスがあるかを検索します。もしなければ、次のShieldFactory::GetObject関数に委任します。
// WeaponFactory::GetObject関数内
handler->GetObject(ID_LONGSWORD); // handlerにはShieldFacoryが登録
ShieldFactoryオブジェクト内でさらに検索が行われ、なければ次のSwordFactoryオブジェクトへ続きます。
// ShieldFactory::GetObject関数内
handler->GetObject(ID_LONGSWORD); // handlerにはSwordFacoryが登録
SwordFactory内にLongSwordの生成機構があれば、そのポインタを返すようにします。ない場合、handlerには何も登録されていない(=NULL)ので、NULLを返すようにします。
// SwordFactory::GetObject関数内
switch
{
case ID_LONGSWORD: // 長剣
return new LongSword;
break;
default:
// 登録されているオブジェクトに委任
if(handler)
handler->GetObject(ID_LONGSWORD);
break;
}
return NULL; // 該当なし
Chain of Responsiblitiyパターンの関係図を示します。
このパターンはイベント(メッセージ)の解釈をさせる時に威力を発します。クライアントが何らかのイベントを発した時、それを共通の関数で解釈し、該当するクラスでそれに対する反応を起こします。Windowsのようなメッセージ駆動型プログラムでは、メッセージハンドラ関数内が長いswitch〜caseになってしまいますが、このパターンを用いると、ハンドラ部分が非常にシンプルな構造になります。