切换语句的替代方法

时间:2018-02-16 12:53:26

标签: c# design-patterns architecture

根据一些文章:

该理论认为这很容易,但实际上这通常很困难。 没关系。让我们了解这件事的核心。

代码如下所示:

    public class SomeType
    {
        // Some properties.
    }

    public enum SomeTrigger
    {
        Loaded,
        Initial,
        Timer,
        Final
    }


    public class SomeBaseObject
    {
        // 
        // I am not allowed to change this class. It is not mine.
        //

        protected Dictionary<string, SomeType> Input;
        protected Dictionary<string, SomeType> Output;


        // Timer is evaluated every 2 sec.
        public virtual void Execute(SomeTrigger trigger, string value)
        {
            switch (trigger)
            {
                case SomeTrigger.Loaded:
                    break;
                case SomeTrigger.Initial:
                    break;
                case SomeTrigger.Timer:
                    break;
                case SomeTrigger.Final:
                    break;
                default:
                    break;
            }
        }

        // The rest of code...
    }

我要改进的课程:

public class SomeSpecificObject : SomeBaseObject
    {
        private bool isInitializationCompleted;
        private string connection;

        public override void Execute(SomeTrigger trigger, string value)
        {
            switch (trigger)
            {
                case SomeTrigger.Loaded:
                    this.OnLoaded();
                    break;
                case SomeTrigger.Initial:
                    this.OnInitial();
                    break;
                case SomeTrigger.Timer:
                    this.OnTimer();
                    break;
                case SomeTrigger.Final:
                    this.OnFinal(value);
                    break;
                default:
                    break;
            }
        }

        private void OnLoaded()
        {
            // Read Input and Output collection.
        }

        private void OnInitial()
        {
            // Initialization (connect to the server).
            // Bla bla bla
            this.connection = //Value from the plug-in;
            this.isInitializationCompleted = true;

        }

        private void OnTimer()
        {
            if (isInitializationCompleted)
            {
                // Do something
                // Connection is using here.
                // Calculate values on a Input collection, etc.
            }
        }

        private void OnFinal(string value)
        {
            if (isInitializationCompleted)
            {
                // something with "value"
                // Connection is using here.
                // Clear state.
            }
            else
            {
                // Connection is using here.
                // Cancel inistialization
            }
        }
    }

我该怎么办?每个领域都在使用但每个触发器。另外,一个案例有点具体(OnFinalMethod需要参数)。基于上面的文章,我试图重构这段代码,但没有成功。

My attempts to apply some tips: 

    public interface ITrigger
    {
        void Execute();
    }

    public class LoadedTrigger : ITrigger
    {
        public void Execute()
        {
            throw new NotImplementedException();
        }
    }

    //
    // Exactly the same class for the rest cases.
    //
    public class TriggerHandler
    {
        private Dictionary<SomeTrigger, ITrigger> triggerDictionary;

        public TriggerHandler()
        {

            triggerDictionary.Add(SomeTrigger.Loaded, new InitialTrigger());
    // and for the rest

        }

        public void HandleTrigger(SomeTrigger trigger)
        {
            triggerDictionary[trigger].Execute();
        }
    }

对象如何相互通信?例如。 TimerTrigger对象需要知道启动成功。我该如何处理特殊情况对象?

有什么想法吗? :)

2 个答案:

答案 0 :(得分:1)

首先,一般来说,switch语句没有任何问题。只是在代码中使用它会产生一些隐含的结构限制。如果其中一个限制与代码演变的方式相矛盾,换句话说,如果需求以切换逻辑变得过时的方式发生变化,那么继续在代码中使用它会导致技术债务。

从上面的代码中不清楚它的要求是什么。例如,为什么要求首先使用Execute方法?它可以直接替换为Loaded(),Initial()和其他方法吗?这显然会消除转换。

另一种方法是使用事件对象而不是枚举并使用方法重载:执行(LoadedTrigger ...),...,执行(FinalTrigger ...,...)。

如果你想在运行时添加处理程序,那么使用字典的方法很好(对吗?),但缺少的部分是检查触发器类型并调用不同的execute方法:

var t = triggerDictionary[trigger];
if (t is SimpleTrigger st) st.Execute();
else if (t is AdvancedTrigger at) at.Execute(value);

或者,为触发器的execute方法添加值。但如果没有这样的要求,为什么要打扰?

  

E.g。 TimerTrigger对象需要知道启动成功。

您可能想要一台状态机。 switch是一种经常用于编码简单状态机转换的方法。

答案 1 :(得分:0)

作为其中一种方法,您可以使用template method。使用此模式,您的代码将如下所示:

public class SomeType
{
    // Some properties.
}

public enum SomeTrigger
{
    Loaded,
    Initial,
    Timer,
    Final
}

public abstract class SomeBaseObject
{
    // 
    // I am not allowed to change this class. It is not mine.
    //

    protected Dictionary<string, SomeType> Input;
    protected Dictionary<string, SomeType> Output;


    // Timer is evaluated every 2 sec.
    public void Execute(SomeTrigger trigger, string value)
    {
        switch (trigger)
        {
            case SomeTrigger.Loaded:
                OnLoaded();
                break;
            case SomeTrigger.Initial:
                OnInitial();
                break;
            case SomeTrigger.Timer:
                OnTimer();
                break;
            case SomeTrigger.Final:
                OnFinal(value);
                break;
            default:
                break;
        }
    }

    protected abstract void OnLoaded();

    protected abstract void OnInitial();

    protected abstract void OnTimer();

    protected abstract void OnFinal(string value);
}

public class SomeSpecificObject : SomeBaseObject
{
    private bool isInitializationCompleted;
    private string connection;



    protected override void OnLoaded()
    {
        // Read Input and Output collection.
    }

    protected override void OnInitial()
    {
        // Initialization (connect to the server).
        // Bla bla bla
        this.connection = "";//Value from the plug-in;
        isInitializationCompleted = true;

    }

    protected override void OnTimer()
    {
        if (isInitializationCompleted)
        {
            // Do something
            // Connection is using here.
            // Calculate values on a Input collection, etc.
        }
    }

    protected override void OnFinal(string value)
    {
        if (isInitializationCompleted)
        {
            // something with "value"
            // Connection is using here.
            // Clear state.
        }
        else
        {
            // Connection is using here.
            // Cancel inistialization
        }
    }
}

如果需要,您可以提供OnXXX方法的默认实现并将其标记为虚拟