Chain of Responsibility

受託開発担当のRyuです。

デザインパターンは数ありますが、私が学んだときどうしても用途がよくわからないパターンがいくつかありました。
今回はその中のひとつ、Chain of Responsibilityパターンについてです。

Chain of Responsibilityパターンはチェーンを使用して、各関数に処理の可否を委ねるものです。
このパターンを知ったとき最初に持った感想は、上位部分で分岐させてしまえばいいのでは?というものです。
わざわざ関数に判断させても、呼び出しのオーバヘッド分遅くなるだけだろうと。
そんな中、以下のようなコードに出会いました。

void Method1(int hoge)
{
	switch (条件)
	{
		case 条件A:
			MethodA(hoge);
			break;
		case 条件B:
			MethodB(hoge);
			break;
	}
}

void Method2(int hoge)
{
	switch (条件)
	{
		case 条件A:
			MethodA(hoge);
			break;
		case 条件B:
			MethodB(hoge);
			break;
		case 条件C:	// Method1には存在しない
			MethodC(hoge);
			break;
	}
}

似たような分岐が存在しています。
このままでもいいのですが、今後Method3, Method4と増えていき条件Aと条件Cのみ、条件Dが追加されるなどの可能性があったので、もう少し扱いやすい形にしようと考えました。

void Method1(int hoge)
{
	if (ExecuteMethodA(hoge)) return;
	if (ExecuteMethodB(hoge)) return;
}
void Method2(int hoge)
{
	if (ExecuteMethodA(hoge)) return;
	if (ExecuteMethodB(hoge)) return;
	if (ExecuteMethodC(hoge)) return;
}

// MethodB(), MethodC()についても同様のものを作成する
bool ExecuteMethodA(int hoge)
{
	if (!条件A)
		return false;

	MethodA(hoge);
	return true;
}

結果上記のような形に。
重複していた条件部分を外に出して、変更に少し強くなりました。
今後Method3, Method4と増えていっても扱いやすい形にもなりました。
しかしMethod1, Method2だけを見た場合、何をしているのか少し見通しが悪くなった感じがします。

そしてここで気づきました。
この形はインターフェイスを使用していないもののChain of Responsibilityパターンなのではないかと。
これまで分岐はなるべく上位に、とにかく少なくと考えていましたが、分岐自体をバラバラにしてしまうことで分岐の数は増えても保守性の高いものを作成できることに気づかされました。

この件以来、私はChain of Responsibilityパターンがとても好きになりました。