インターフェースを考える(5)IAction その2
前回に続きIActionについて考える。
IPredicateやITaskと同じように組み合わせ用にCompositeActionクラスを作る。
using System; using System.Collections.Generic; namespace Nmdm.Actions { public sealed class CompositeAction<TContext> : IAction<TContext> { public CompositeAction(IEnumerable<IAction<TContext>> actions) { if (actions == null) throw new ArgumentNullException("actions"); this.Actions = actions; } private IEnumerable<IAction<TContext>> Actions { get; } public void Do(TContext context) { foreach(var obj in this.Actions) { obj.Do(context); } } } }
IPredicateの時も気になったけど、このクラスを使う時にList型の変数を使ってIActionをコレクションに入れてからコンストラクタを呼び出すのかって考えるといまいちな感じがする。
かといって、クラスは基本不変にしたい・・・・
ということで↓へ改造
using System; using System.Collections.Generic; namespace Nmdm.Actions { public sealed class CompositeAction<TContext> : IAction<TContext> { public CompositeAction() { this.Actions = new IAction<TContext>[] { }; } private CompositeAction(IEnumerable<IAction<TContext>> actions) { if (actions == null) throw new ArgumentNullException("actions"); this.Actions = actions; } private IEnumerable<IAction<TContext>> Actions { get; } public CompositeAction<TContext> Add(IAction<TContext> action) { if (action == null) throw new ArgumentNullException("actions"); var actions = new List<IAction<TContext>>(this.Actions); actions.Add(action); return new CompositeAction<TContext>(actions); } public void Do(TContext context) { foreach(var obj in this.Actions) { obj.Do(context); } } } }
コンストラクタをプライベートにしてAddメソッドを追加、メソッドの戻り値でprivateなコンストラクタで生成した結果を返して不変かつ流暢なインターフェースに。
このクラス自体がIActionを実装しているからAddRangeメソッドはいらないと思う。
ついでにIActionの受け口をAddメソッドだけにしたから個々の要素に対してもnullチェックが出来ている。
元のソースと比べると複雑さが増しているけどIAction以外への依存はなく変更の可能性が低いから良いかと思います。
==2017.03.14追記===
やっぱり改造やめ、読みにくいから、というならまだしも、
書きにくいから、という理由でメソッドを増やすのに少し抵抗を感じる。