[C#]型によって処理をグループ化する

# 概要
自作クラス（型）によって処理を分ける。

# クラス構成
- **Actionクラス
    - 処理の単位になる型。処理に必要な固有情報を持ってる。
- Dispatcherクラス
    - 処理をためるシングルトンクラス。
- TODOStoreクラス
    - **Actionクラスごとに実行する処理を設定する。

# サンプル


## アクションクラス
```C#
    public class CreateItemAction
    {
        public CreateItemAction(string message)
        {
            Message = message;
        }

        public string Message { get; private set; }
    }
    public class WriteItemAction { }
    public class IntAction
    {
        public IntAction(int id) => this.id = id;
        public int id;
    }
```
これらをDispatcherクラスに渡すとDispatcherクラスが型によって処理を分けて実行してくれる。

- CreateItemActionクラスはItemを作成する処理をする型
- WriteItemActionクラスは画面にItemを表示する型
- IntActionクラスはIdを指定してItemを作成する型


## dispatcherクラス
```C#
   class Dispatcher
    {
        //singleton
        private static readonly Dispatcher disp = new Dispatcher();
        public static Dispatcher Instance => disp;
        private Dispatcher() { }

        Dictionary<Type, IList<object>> dic = new Dictionary<Type, IList<object>>();
        public void Resist<T>(Action<T> a)
        {
            var key = typeof(T);
            if (!dic.ContainsKey(key)) dic.Add(key, new List<object>());
            dic[key].Add(a);
        }

        public void Dispatch<T>(T payload)
        {
            var key = typeof(T);
            if (!dic.ContainsKey(key)) return;

            dic[key].OfType<Action<T>>()
                    .ToList()
                    .ForEach(call => call(payload));
        }
    }
```
Resistは型ごとに処理をためるメソッド。
Dispatchは型ごとに処理を実行するメソッド。

## TODOStoreクラス
```C#
    class TODOStore
    {
        public Dispatcher AppDispatcher { get; private set; } = Dispatcher.Instance;
        private Dictionary<string, TODOItem> items = new Dictionary<string, TODOItem>();
        private readonly Random random = new Random();

        public TODOStore()
        {
            AppDispatcher.Resist<CreateItemAction>(
                c =>
                {
                    var newText = c.Message;
                    if (string.IsNullOrWhiteSpace(newText)) return;
                    Create(newText);
                }
            );
            AppDispatcher.Resist<WriteItemAction>(
                c =>
                {
                    PrintItem();
                }
            );
            AppDispatcher.Resist<IntAction>(
                c =>
                {
                    var id = c.id;
                    if (id == 0) return;
                    Create(id);
                }
            );
        }
        void Create(string newText)
        {
            var now = DateTime.Now;
            var offset = Math.Floor(((random.NextDouble() + random.NextDouble()) / 2) * 999999);

            var id = $"{now}-{offset}";
            var item = new TODOItem
            {
                Text = newText,
                Id = id,
            };

            items[id] = item;
        }
        void Create(int id)
        {
            var item = new TODOItem
            {
                Text = "default",
                Id = id.ToString(),
            };
            items[id.ToString()] = item;
        }
        void PrintItem()
        {
            foreach (var i in items)
            {
                WriteLine($"{i.Value.Id}  {i.Value.Text}");
            }
        }
    }
```
TODOStoreクラスは実際の処理を指定するクラス。
コンストラクターでそれぞれのActionクラスごとに何をするかを定義する。
IntActionの場合、Idが被っていると上書きされる。
## 使う側
```C#
        static void Main(string[] args)
        {
            string[] mes = { "new-Item1", "new-Item2", "new-Item3", };
            new TODOStore();
            var ia = new IntAction(1);
            CreateItemAction[] cia =
            {
                new CreateItemAction(mes[0]),
                new CreateItemAction(mes[1]),
                new CreateItemAction(mes[2]),
            };

            var writeAction = new WriteItemAction();

            Dispatcher.Instance.Dispatch(cia[0]);
            Dispatcher.Instance.Dispatch(cia[1]);
            Dispatcher.Instance.Dispatch(cia[2]);
            Dispatcher.Instance.Dispatch(ia);
            Dispatcher.Instance.Dispatch(ia);
            Dispatcher.Instance.Dispatch(writeAction);
        }
```
これを実行すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47053/635d060e-c200-02bf-cf16-fdba9b9171fe.png)

こうなる。

# その他

Fluxパターンについて調べていたところ、GUI以外も使いどころありそうと思ったのでメモ。
shiftkeyさんのリポジトリが神。https://github.com/shiftkey/fluxsharp-proof-of-concept