5

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

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

しかし、私が意図した条件付きのWhenを実装するのに問題があります。現在、このスニペットのようにWhen()を2回呼び出す必要があります。

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のサブクラスをサポートする必要があります(おそらくその部分にジェネリックを使用しています)。私はすべて私のデザインに混乱していて、マーティン・ファウラーの記事が私をさらに混乱させているので、ここに投稿しています。

4

1 に答える 1

3

これは、メソッドチェーンの場合の仕上げの問題として知られています。 これを試してください

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

最初は少し奇妙に見えますが、条件付きで実行できるように、条件を別のスコープにラップします。独自のifブロックを作成するようなものだと考えてください。それを閉じることで、いつサブステートメントを「終了」できるかがわかります。

于 2009-07-27T19:15:16.443 に答える