意思決定表は、条件のグループを表として表現することによって理解しやすくしてくれます。各列がある特定の組み合わせの条件による結果を示しています。
class DecisionTable <Tin, Tout>{ readonly List<Condition<Tin>> conditions = new List<Condition<Tin>>(); readonly List<Column<Tout>> columns = new List<Column<Tout>>();
class DecisionTable... public void AddCondition(string description, Condition<Tin>.TestType test) { conditions.Add(new Condition<Tin>(description, test)); } public class Condition<T> { public delegate bool TestType(T input); public string description { get; private set; } public TestType Test { get; private set; } public Condition(string description, TestType test) { this.description = description; this.Test = test; } }
var decisionTable = new DecisionTable<Order, FeeResult>(); decisionTable.AddCondition("Premium Customer", o => o.Customer.IsPremium); decisionTable.AddCondition("Priority Order", o => o.IsPriority); decisionTable.AddCondition("Priority Order", o => o.IsInternational);
class FeeResult { public int Fee { get; private set; } public bool shouldAlertRepresentative { get; private set; } public FeeResult(int fee, bool shouldAlertRepresentative) { Fee = fee; this.shouldAlertRepresentative = shouldAlertRepresentative; }
class Column <Tresult> { public Tresult Result { get; private set; } public readonly ConditionBlock Conditions; public Column(ConditionBlock conditions, Tresult result) { this.Conditions = conditions; this.Result = result;
interface ITable { string cell(int row, int col); int RowCount {get;} int ColumnCount {get;} }
class TableParser... private readonly DecisionTable<Order, FeeResult> result = new DecisionTable<Order, FeeResult>(); private readonly ITable input; public TableParser(ITable input) { this.input = input; } public DecisionTable<Order, FeeResult> Run() { loadConditions(); loadColumns(); return result; }
class TableParser... private void loadConditions() { result.AddCondition("Premium Customer", (o) => o.Customer.IsPremium); result.AddCondition("Priority Order", (o) => o.IsPriority); result.AddCondition("International Order", (o) => o.IsInternational); checkConditionNames(); }
class TableParser... private void checkConditionNames() { for (int i = 0; i < result.ConditionNames.Count; i++) checkRowName(i, result.ConditionNames[i]); } private void checkRowName(int row, string name) { if (input.cell(row, 0) != name) throw new ArgumentException("wrong row name"); }
class TableParser... private void loadColumns() { for (int col = 1; col < input.ColumnCount; col++ ) { var conditions = new ConditionBlock( Bool3.parse(input.cell(0, col)), Bool3.parse(input.cell(1, col)), Bool3.parse(input.cell(2, col))); var consequences = new FeeResult( Int32.Parse(input.cell(3, col)), parseBoolean(input.cell(4, col)) ); result.AddColumn( conditions, consequences); } }
class Bool3... public static Bool3 parse (string s) { if (s.ToUpper() == "Y") return T; if (s.ToUpper() == "N") return F; if (s.ToUpper() == "X") return X; throw new ArgumentException( String.Format("cannot turn <{0}> into Bool3", s)); } class TableParser... private bool parseBoolean(string arg) { if (arg.ToUpper() == "Y") return true; if (arg.ToUpper() == "N") return false; throw new ArgumentException( String.Format("unable to parse <{0}> as boolean", arg)); }