【问题标题】:Implementing conditional in a fluent interface在流畅的界面中实现条件
【发布时间】:2009-07-27 19:01:38
【问题描述】:

我一直在尝试为我的系统中的一组规则实现一个流畅的界面。我想要完成的是这个

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

但是,我在实现When 条件时遇到了问题。目前,我需要像在这个 sn-p 中那样调用 When() 两次:

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 让我更加困惑。

【问题讨论】:

  • 你有没有让这个实现完全工作?奇怪的是,关于这个话题并没有那么多!您可以发布您对此问题的工作解决方案或直接发送给我吗?谢谢!

标签: c# oop .net-2.0 fluent-interface


【解决方案1】:

method chaining 试试这个

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

一开始看起来有点奇怪,但它把你的条件包装到一个不同的范围内,这样你就可以有条件地执行它们。把它想象成创建你自己的 if 块。通过关闭它,您知道何时可以“完成”子语句。

【讨论】:

  • 第二个参数是表达式树对吧?因为它需要创建一个规则类的新实例。问题是我不能使用表达式树,因为它是一个 .NET 2.0 项目。我使用 C# 3.0 编译器的思路
  • 这只是一个 lambda。如果您只能使用 C# 2.0,请尝试匿名委托 msdn.microsoft.com/en-us/library/0yw3tz5k(VS.80).aspxWhen(quartType => quartType==QuartType.After, delegate(Rule rule){ rule.TotalMillageIs(128)) 如果这不起作用,如何: When(quartType => quartType == QuartType.After, Rule.TotalMilageIs(128)) 并创建一个稍后应用的新规则。这样做的主要缺点是您可能有两种类型的规则,实例规则和应用规则。您也许可以将它们组合在一起。
猜你喜欢
  • 1970-01-01
  • 2010-09-29
  • 2015-01-06
  • 2010-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多