避免长切换/ if用于处理函数

时间:2018-06-17 10:58:41

标签: c# oop state-machine

我发现我经常写这样的代码:

class SomeClass
{
    HandleOtherClass(OtherClass otherClass)
    {
        switch (otherClass.State)
        {
            case OtherClassState.Unstarted:
                this.HandleUnstarted(situation);
                break;
            case OtherClassState.New:
                this.HandleNew(situation);
                break;
            case OtherClassState.Ongoing:
                this.HandleOngoing(situation);
                break;
            case OtherClassState.Stale:
                this.HandleStale(situation);
                break;
            case OtherClassState.Complete:
                this.HandleComplete(situation);
                break;
            default:
                throw new NotImplementedException();
                break;
        }
    }
}

它有效,但似乎我错过了一些可以使这段代码更易于维护的模式。我通常会在OO中读到if / switch语句应该被考虑在内。我考虑过一本字典,但只是将代码移动了一下而没有真正改变架构。我怎么能更好地处理这个?

2 个答案:

答案 0 :(得分:1)

当您想扩展案例时,还有一些额外的复杂性需要考虑,特别是当您的同事没有参加过逻辑设计课程时:

HandleOtherClass(OtherClass otherClass)
{
    switch (otherClass.State)
    {
        case OtherClassState.Unstarted:
            // this can become quite complicated.
            switch(yetAnotherState)
            { 
                 case 1:
                     //do stuff
                     break
                 case 2:
                     //etc
                     break;
            }
            break;
        case OtherClassState.New:
            this.HandleNew(situation);
            break;
        default:
            throw new NotImplementedException();
            break;
    }
}

处理此重复设计问题的典型方法是state pattern。我必须说,它也可能变得非常麻烦,但拥有它至少会引导你进入“一个人”。状态机,而不是在任何地方重写代码,一般来说,我们力求可读性和可维护性。

以下是状态模式的典型包装示例(取自this实现),这些是常用的,因为它们的语法消除了类中已实现状态的复杂性:

var phoneCall = new StateMachine<State, Trigger>(State.OffHook);

phoneCall.Configure(State.OffHook)
    .Permit(Trigger.CallDialled, State.Ringing);

phoneCall.Configure(State.Ringing)
    .Permit(Trigger.CallConnected, State.Connected);

phoneCall.Configure(State.Connected)
    .OnEntry(() => StartCallTimer())
    .OnExit(() => StopCallTimer())
    .Permit(Trigger.LeftMessage, State.OffHook)
    .Permit(Trigger.PlacedOnHold, State.OnHold);

// ...

phoneCall.Fire(Trigger.CallDialled);
Assert.AreEqual(State.Ringing, phoneCall.State);

正如你所看到的,有states(例如:OffHook),并且在这种状态下,通常通过事件(例如:PickedUp)转换到或不允许转换到另一个状态。发生此类转换时,将执行操作。

答案 1 :(得分:1)

现在的问题含糊不清。

如果需要状态模式,请在派生状态(例如NewState)上实现句柄。 调用对象的句柄,调用state.Handle()

如果要动态委托方法重载,请实现Handle(State1 s),Handle(State2 s)等。通过将状态转换为dynamic来调用它们,因此:Handle((dynamic)state)