グローバル変数を避けるため、DSLの関数は基底クラスに定義し、サブクラスで利用する。
定義したいルール
class MyZone : ZoneBuilder { protected override void doBuild() { Allow( Department("MF"), Until(2008, 10, 18)); Refuse(Department("Finance")); Refuse(Department("Audit")); Allow( GradeAtLeast(Grade.Director), During(1100, 1500), Until(2008, 5, 1)); }
抽象入場ルールクラス
abstract class AdmissionRule { protected RuleElement body; protected AdmissionRule(RuleElement body) { this.body = body; } public abstract AdmissionRuleResult CanAdmit(Employee e); } enum AdmissionRuleResult {ADMIT, REFUSE, NO_OPINION};
※実装クラスとして許可ルールと拒否ルールができる。
ルールを使うzoneクラス
class Zone... private IList<AdmissionRule> rules = new List<AdmissionRule>(); public void AddRule(AdmissionRule arg) { rules.Add(arg); } public bool WillAdmit(Employee e) { foreach (AdmissionRule rule in rules) { switch(rule.CanAdmit(e)) { case AdmissionRuleResult.ADMIT: return true; case AdmissionRuleResult.NO_OPINION: break; case AdmissionRuleResult.REFUSE: return false; default: throw new InvalidOperationException(); } } return false; }
スコーピングのための基底クラス
class ZoneBuilder... private Zone zone; public ZoneBuilder Allow(params RuleElement[] rules) { AndExpr expr = new AndExpr(rules);
zone.AddRule(new AllowRule(expr)); return this; }