重构:用Command替换条件调度程序

注:该随笔受启发于 《重构与模式》  第七章 第7.6小节 用Command替换条件调度程序 。

对于Command不做过多解释,这里我找了两个例子、供部分园友参阅:Command例子1 Command例子2 。

条件调度程序:我对这个名词的理解为,它是相对简单的选择结构 与 相对独立的业务逻辑的结合体。

话不是很好理解,下面举个小例子吧。

重构前的代码:

  /// <summary>
        /// 很简单的选择分支 一层 if else
        /// N个 相对独立 任务
        /// </summary>
        /// <param name="actionName"></param>
        public void DoAction(string actionName)
        {
            if (actionName == "Action1")
            {
                // 处理 Action1任务
                Console.WriteLine("执行任务1");
            }
            else if (actionName == "Action2")
            {
                // 处理 Action2任务
                Console.WriteLine("执行任务2");
            }
            else if (actionName == "Action3")
            {
                // 处理 Action3任务
                // 无处理操作
            }

        }

在 《重构与模式》 一文中的重构的做法是:

为每一个动作创建一个Command,把这些Command存储在一个集合中, 并用获取及执行Command的代码替换条件逻辑。

重构步骤我不做详细描述,看一下重构后的结果吧:

    public class class2
    {
        private Dictionary<string, CommandAbstract> dic;

        public class2()
        {
            this.dic = new Dictionary<string, CommandAbstract>();
            this.dic.Add("Action1", new Command1());
            this.dic.Add("Action2", new Command2());
            this.dic.Add("Action3", new Command3());
        }

        /// <summary>
        /// 应用 Command模式 替换 条件调度程序/// </summary>
        /// <param name="actionName"></param>
        public void DoAction(string actionName)
        {
            CommandAbstract command = null;

            if (dic.ContainsKey(actionName))
            {
                command = dic[actionName];
            }

            if (command != null)
            {
                command.Execute();
            }
        }
    }

    public abstract class CommandAbstract
    {
        public abstract void Execute();
    }

    public class Command1 : CommandAbstract
    {
        public override void Execute()
        {
            Console.WriteLine("执行任务1");
        }
    }

    public class Command2 : CommandAbstract
    {
        public override void Execute()
        {
            Console.WriteLine("执行任务2");
        }
    }

    public class Command3 : CommandAbstract
    {
        public override void Execute()
        {

        }
    }
  

看着 硬编码 Dictionary 很不爽,如果经常需要添加新Command, 有可能还需要继续重构——使其遵循开闭原则。

方案:使用反射代替硬编码 (简单的Plugin模式),重构后的结果如下:

    public static class CommandFactory
    {
        private static Dictionary<string, CommandAbstract> dic;

        static CommandFactory()
        {
            dic = new Dictionary<string, CommandAbstract>();

            Type absType = typeof(CommandAbstract);

            Assembly assem = absType.Assembly;

            foreach (Type t in assem.GetTypes())
            {
                if (t.IsClass && !t.IsAbstract && t.IsSubclassOf(absType))
                {
                    CommandAbstract command = Activator.CreateInstance(t) as CommandAbstract;

                    if (command != null && !dic.ContainsKey(command.CommandName))
                    {
                        dic.Add(command.CommandName, command);
                    }
                }
            }
        }

        public static CommandAbstract GetCommand(string commandName)
        {
            if (dic.ContainsKey(commandName))
            {
                return dic[commandName];
            }

            return null;
        }

    }

    public class class2
    {/// <summary>
        /// 重构硬编码/// </summary>
        /// <param name="actionName"></param>
        public void DoAction(string actionName)
        {
            CommandAbstract command = CommandFactory.GetCommand(actionName);

            if (command != null)
            {
                command.Execute();
            }
        }
    }

    public abstract class CommandAbstract
    {
        public string CommandName { get; protected set; }

        public abstract void Execute();
    }

    public class Command1 : CommandAbstract
    {
        public Command1()
        {
            this.CommandName = "Action1";
        }

        public override void Execute()
        {
            Console.WriteLine("执行任务1");
        }
    }

    public class Command2 : CommandAbstract
    {
        public Command2()
        {
            this.CommandName = "Action2";
        }

        public override void Execute()
        {
            Console.WriteLine("执行任务2");
        }
    }

    public class Command3 : CommandAbstract
    {
        public Command3()
        {
            this.CommandName = "Action3";
        }

        public override void Execute()
        {

        }
    }

如果 条件表达式 较为复杂呢,那又可以怎样重构?

提示:责任链模式。

时间: 2024-10-09 16:52:13

重构:用Command替换条件调度程序的相关文章

重构第四天 : 用多态替换条件语句(if else &amp; switch)

面相对象的一个核心基础就是多态,当你要根据对象类型的不同要做不同的操作的时候,一个好的办法就是采用多态,把算法封装到子类当中去. 重构前代码: 1 public abstract class Customer 2 { 3 } 4 5 public class Employee : Customer 6 { 7 } 8 9 public class NonEmployee : Customer 10 { 11 } 12 13 public class OrderProcessor 14 { 15

重构第六天:用条件语句替换异常

在工作中经常遇到用异常去控制程序流程,下面是一个普遍的例子: public class Microwave { private IMicrowaveMotor Motor { get; set; } public bool Start(object food) { bool foodCooked = false; try { Motor.Cook(food); foodCooked = true; } catch (InUseException) { foodcooked = false; }

利用反射+多态替换条件语句

/*利用反射+多态替换条件语句*/ class Program { public static void Main(string[] args) { /* * 用户发送一个命令,让代码去指定Commander * * <?xml version="1.0" encoding="utf-8" ?><Command><CommandType>Start</CommandType></Command> */ //

重构摘要9_简化条件表达式

<重构-改善既有代码的设计>Martin Fowler 摘要: 第九章 简化条件表达式 Decompose Conditinal 分解条件表达式 你有一个复杂的条件(if-then-else)语句 从三个段落中分别提炼出独立函数 Consolidate Conditional Expression 合并条件表达式 你有一系列条件测试,都得到相同结果 将这些测试合并成为一个条件表达式,并将这个条件表达式提炼成为一个独立函数 检查用意更清晰,有时也不用这么做 Consolidate Duplica

【重构学习】08 条件表达式的重构

所谓条件表达式,就是分支语句,去掉分支语句咯 1.分解条件表达式 修改点:你有一个复杂的条件语句(就是if else语句) 做法:将条件表达式的三个部分分别提炼出独立函数 即 if (A部分) { B部分; } else { C部分; } 这三个部分都提炼成函数就好了. 2.合并条件表达式 修改点:你有一系列测试,都得到相同结果 做法:将这些测试合并成一个条件表达式,并将这个表达式提炼成一个独立函数 3.合并重复的条件片段 修改点:在条件表达式的每个分支上有着相同一段代码 做法:将这段重复代码搬

小酌重构系列[23]&mdash;&mdash;封装条件

概述 当条件判断语句较为复杂时(有多个不同的检查项),就像下面这幅图所表示的,会使得代码的可读性会大打折扣,也难以清晰地传达判断意图. 再者,当判断逻辑变更时,我们不得不去修改if语句里面的判断代码.如果判断写得有问题,则会影响方法的正确性,也会给该方法的单元测试带来一些障碍. 我们可以根据检查项是否需要参数来封装条件,如果检查项不需要参数,则可以将其提取为属性:如果需要参数,则将其提取为方法.本文要讲的重构策略"封装条件"是基于"提取方法"这个重构策略的. 示例

小酌重构系列[20]&mdash;&mdash;用条件判断代替异常

概述 异常处理的关键在于何时处理异常以及如何使用异常,有些开发者会觉得try catch的处理和使用难以把握,于是他们秉承着"您可错杀一千,不可放过一个"的想法,给所有的方法添加try catch. 这种方式会对应用程序造成什么影响吗? 从用户角度出发,用户确实难以察觉到什么,应用程序运行正常,使用的体验好像也没什么差别. 从程序角度出发,大量的try catch会降低代码的可读性,只有在异常触发时才会对程序的性能造成较大的影响. 这两种角度有对错吗? 二者都没有错,第一种角度甚至要远

小酌重构系列[23]——封装条件

当条件判断语句较为复杂时(有多个不同的检查项),就像下面这幅图所表示的,会使得代码的可读性会大打折扣,也难以清晰地传达判断意图. 再者,当判断逻辑变更时,我们不得不去修改if语句里面的判断代码.如果判断写得有问题,则会影响方法的正确性,也会给该方法的单元测试带来一些障碍. 我们可以根据检查项是否需要参数来封装条件,如果检查项不需要参数,则可以将其提取为属性:如果需要参数,则将其提取为方法.本文要讲的重构策略“封装条件”是基于“提取方法”这个重构策略的. 示例 重构前 这个示例中,PerformC

重构手法之简化条件表达式【1】

返回总目录 本小节目录 Decompose Conditional(分解条件表达式) Consolidate Conditional Expression(合并条件表达式) 1Decompose Conditional(分解条件表达式) 概要 你有一个复杂的条件(if-else if-else)语句. 从if.else if.else三个段落中分别提炼出独立函数. 动机 复杂的条件逻辑往往会导致程序复杂度上升.编写代码来检查不同的条件分支.根据不同的分支做不同的事往往又会导致函数过长. 将条件表