1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【C#】ラムダ式で楽してChain of Responsibilityパターンを書こう

Last updated at Posted at 2022-05-24

この記事の目的

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パターンは、デザパタ本通りに書くと
仕組みを作ったり、具象処理ごとにクラスを作成しないといけなかったりしてコード量が多くなります。
省略できる書き方があると楽できていいですね。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?