この記事の目的
Chain of Responsibilityパターンでコードを書きたいけど、
仕組みを一から作るのは面倒というときに使えるC#の汎用クラスを書いてみたので紹介します。
作成した汎用クラスに、ラムダ式で具象処理を投げることで、少ないコード量で
Chain of Responsibilityパターンを実装します。
Chain of Responsibility汎用クラス
public class ChainAction<T>
{
public Action<T> Action { get; set; }
public Func<T, bool> CanInvoke { get; set; }
}
public class ChainOfResponsibility<T>
{
List<ChainAction<T>> ChainActions { get; set; } = new List<ChainAction<T>>();
public ChainOfResponsibility<T> Next(ChainAction<T> chainAction)
{
ChainActions.Add(chainAction);
return this;
}
public void Invoke(T value)
{
foreach(var chainAction in ChainActions)
{
if (chainAction.CanInvoke(value))
{
chainAction.Action(value);
return;
}
}
}
}
使用例
int testInt = default(int);
var chain = new ChainOfResponsibility<int>();
var chainAction1 = new ChainAction<int> { Action = x => testInt = x + 1, CanInvoke = x => { return (x == 100); } };
var chainAction2 = new ChainAction<int> { Action = x => testInt = x + 2, CanInvoke = x => { return (x == 200); } };
var chainAction3 = new ChainAction<int> { Action = x => testInt = x + 3, CanInvoke = x => { return true; } };
chain.Next(chainAction1).Next(chainAction2).Next(chainAction3);
chain.Invoke(200);
Assert.AreEqual(testInt, 202); // 単体試験メソッド 結果はOKになる
使用方法
1.ChainOfResponsibilityクラスのインスタンスを生成します。
ジェネリックの型<>には処理したい変数の型を書いておいてください。
var chain = new ChainOfResponsibility<int>();
2.ChainActionクラスを作成しましょう。
Actionプロパティには、実際に行う処理を入れてください。
CanActionプロパティには、Actionプロパティに入れた処理を、実行するかどうか判定する式を入れてください。
// 読みやすくするために改行してみた
var chainAction1 = new ChainAction<int> {
Action = x => testInt = x + 1,
CanInvoke = x => { return (x == 100); }
};
// 別に1行で書いてもいい
var chainAction2 = new ChainAction<int> { Action = x => testInt = x + 2, CanInvoke = x => { return (x == 200); } };
// 最後に実行するメソッドはCanInvokeでそのままtrueを返しておくといいかも
var chainAction3 = new ChainAction<int> { Action = x => testInt = x + 3, CanInvoke = x => { return true; } };
3.手順1で生成したChainOfResponsibilityクラスのNextメソッドを実行していきます。
Nextメソッドの戻り値でChainOfResponsibilityクラスが返ってくるので、
そのままNextで指定できます。
(よく見る書き方です。これがやりたかった……)
chain.Next(chainAction1).Next(chainAction2).Next(chainAction3);
4.最後にInvokeメソッドで実行です。
引数に処理したい変数を入れてください。
chain.Invoke(200);
あとがき
Chain of Responsibilityパターンは、デザパタ本通りに書くと
仕組みを作ったり、具象処理ごとにクラスを作成しないといけなかったりしてコード量が多くなります。
省略できる書き方があると楽できていいですね。