2009-07-27 18 views
4

私は自分のシステムで一連のルールの流暢なインターフェイスを実装しようとしています。私が達成しようとしているのはこれです。流暢なインターフェイスで条件付きを実装する

TicketRules 
.RequireValidation() 
.When(quartType => quartType == QuartType.Before).TotalMilageIs(64) 
.When(quartType => quartType == QuartType.After).TotalMilageIs(128); 

しかし、いつ私が意図したかという条件を実装するのは難しいです。現在、私は二回、このスニペットのように)場合には(コールする必要があります。

rules.When(param => param.Remarque == "Test").TotalMilageIs(100); 
rules.When(param => param.Remarque == "Other").TotalMilageIs(50); 

var params1 = new AddTicketParameters() { Remarque = "Test" }; 
var params2 = new AddTicketParameters() { Remarque = "Other" }; 

rules.ExecuteWith(params1); 

Assert.That(ticket.TotalMilage, Is.EqualTo(100)); 

rules.ExecuteWith(params2); 

Assert.That(ticket.TotalMilage, Is.EqualTo(50)); 

マイTicketRulesクラスは、このなります

[EditorBrowsable(EditorBrowsableState.Never)] 
public class TicketRules : ITicketRule, IHideObjectMembers 
{ 
    private Ticket theTicket; 

    public Ticket Ticket 
    { 
     set 
     { 
      theTicket = value; 
     } 
    } 

    private List<ITicketRule> allRules = new List<ITicketRule>(); 

    public TicketRules() 
    { 
    } 

    public TicketRules(Ticket ticket) 
    { 
     theTicket = ticket; 
    } 

    public void Execute() 
    { 
     ExecuteWith(null, null); 
    } 

    public void ExecuteWith(AddTicketParameters param) 
    { 
     ExecuteWith(param, null); 
    } 

    public virtual void ExecuteWith(AddTicketParameters param, Ticket outsideTicket) 
    { 
     foreach (ITicketRule rule in allRules) 
     { 
      rule.ExecuteWith(param, theTicket ?? outsideTicket); 
     } 
    } 

    public TicketRules RequireValidation() 
    { 
     CreateModifierRule(ticket => ticket.NeedValidation = true); 
     return this; 
    } 

    public TicketRules TotalMilageIs(int milage) 
    { 
     CreateModifierRule(ticket => ticket.TotalMilage = milage); 
     return this; 
    } 

    private void CreateModifierRule(Action<Ticket> function) 
    { 
     AddRule(new ModifierTicketRule(function)); 
    } 

    internal void AddRule(ITicketRule rule) 
    { 
     allRules.Add(rule); 
    } 

    public WhenClauseTicketRule When(Predicate<AddTicketParameters> predicate) 
    { 
     WhenClauseTicketRule whenClause = new WhenClauseTicketRule(); 
     whenClause.Predicate = predicate; 

     AddRule(whenClause); 

     return whenClause; 
    } 

    public TicketRules UseStandardFormulaForTotalMilageAndTime() 
    { 
     AddRule(new StandardFormulaTicketRule()); 
     return this; 
    } 

    public TicketRules EnsureMinimumMilageIs(int milage) 
    { 
     AddRule(new EnsureMinimumMilageTicketRule(milage)); 
     return this; 
    } 
} 

ITicketRules

internal interface ITicketRule : IHideObjectMembers 
{ 
    void ExecuteWith(AddTicketParameters param, Ticket ticket); 
} 

を私はまた、サポートする必要がありますWhen節のAddTicketParametersのサブクラス(私はおそらくその部分のジェネリックを使用しています)。私はすべて私のデザインで混乱しているので私はここに投稿しています、そして、Martin Fowler articlesはさらに私を混乱させます。

+0

この実装は完全に機能しましたか?奇妙なことに、実際にはこのトピックにはあまり出ていないことがあります。あなたはこの問題にあなたの実用的な解決策を投稿したり、直接私にそれを送ることができますか?ありがとう! –

答えて

3

method chaining それは最初は少し奇妙に見えますが、あなたは条件付きでそれらを実行することができますので、それは別のスコープにあなたの条件文をラップし、この

TicketRules 
.RequireValidation() 
.When(quartType => quartType == QuartType.Before, 
     rule => rule.TotalMilageIs(64)) 
.When(quartType => quartType == QuartType.After, 
     rule => rule.TotalMilageIs(128)); 

をしようとすると、これは仕上げの問題として知られています。もしあなたが自分のブロックを作成するように考えてみてください。これを閉じると、サブステートメントを「終了」することができます。

+0

2番目の引数は式ツリーです。ルール・クラスの新しいインスタンスを作成する必要があるためです。 問題は、.NET 2.0プロジェクトであるため、式ツリーを使用できないことです。私はC#3.0コンパイラの考えを使用する –

+0

それは単なるラムダです。 C#2.0のみを使用できる場合は、匿名のデリゲートを試してみてください。http://msdn.microsoft.com/en-us/library/0yw3tz5k(VS.80).aspx (quartType => quartType == QuartType.After、デリゲート(ルールルール){rule.TotalMillageIs(128)) 問題が解決しない場合は、方法について: とき(quartType => quartType == QuartType.After、Rule.TotalMilageIs(128)) し、Create後で適用される新しいルール。主な欠点は、インスタンスルールと適用ルールという2種類のルールがあることです。それらを一緒に因数分解することができるかもしれません。 – Ball

+0

ヒントのおかげで。 –

関連する問題