http://bj007.blog.51cto.com/1701577/345100/

switch语句是我们日常工作中最常见也是争论最多的(goto被忽视的前提下)。在重构中也把switch语句看成是一种代码的坏味道。但如何改造现有的switch代码并在今后去避免呢?本文从两方面进行探讨。
1 类型转化 
    在不同的抽象层次上对于同一个对象可能会用不同的定义。举个简单的例子,在计算器中,用户输入的操作符号可能是字符型的,而程序内部实现的时候需要用枚举型。因此可能就会有这样的函数。

C#: switch语句的重构『网摘』-LMLPHP        public class Calculator 
C#: switch语句的重构『网摘』-LMLPHP        { 
C#: switch语句的重构『网摘』-LMLPHP                public enum OPERATOR {Add, Minus, Multiply, Divide, Unknown};
C#: switch语句的重构『网摘』-LMLPHP                public static OPERATOR GetOperator(char ch) 
C#: switch语句的重构『网摘』-LMLPHP                { 
C#: switch语句的重构『网摘』-LMLPHP                        OPERATOR op = OPERATOR.Unknown;
C#: switch语句的重构『网摘』-LMLPHP                        switch (ch) 
C#: switch语句的重构『网摘』-LMLPHP                        { 
C#: switch语句的重构『网摘』-LMLPHP                                case '+': 
C#: switch语句的重构『网摘』-LMLPHP                                        op = OPERATOR.Add; 
C#: switch语句的重构『网摘』-LMLPHP                                        break; 
C#: switch语句的重构『网摘』-LMLPHP                                case '-': 
C#: switch语句的重构『网摘』-LMLPHP                                        op = OPERATOR.Minus; 
C#: switch语句的重构『网摘』-LMLPHP                                        break; 
C#: switch语句的重构『网摘』-LMLPHP                                case '*': 
C#: switch语句的重构『网摘』-LMLPHP                                        op = OPERATOR.Multiply; 
C#: switch语句的重构『网摘』-LMLPHP                                        break; 
C#: switch语句的重构『网摘』-LMLPHP                                case '/': 
C#: switch语句的重构『网摘』-LMLPHP                                        op = OPERATOR.Divide; 
C#: switch语句的重构『网摘』-LMLPHP                                        break; 
C#: switch语句的重构『网摘』-LMLPHP                                default: 
C#: switch语句的重构『网摘』-LMLPHP                                        break; 
C#: switch语句的重构『网摘』-LMLPHP                        } 
C#: switch语句的重构『网摘』-LMLPHP                        return op; 
C#: switch语句的重构『网摘』-LMLPHP                } 
C#: switch语句的重构『网摘』-LMLPHP        }
   代码不长,不过写的过程中我却拷贝几次(case部分的代码)。原因就是代码的结构性重复还是比较严重的,而且如果以后支持其他新的操作时候,这代码不仅要改变,而且还会不断变冗长。认真想想,避免的办法还是有的,用Dictionary做一个映射表就可以实现。

C#: switch语句的重构『网摘』-LMLPHP     public class Calculator 
C#: switch语句的重构『网摘』-LMLPHP        { 
C#: switch语句的重构『网摘』-LMLPHP                public enum OPERATOR { Add, Minus, Multiply, Divide, Unknown};
C#: switch语句的重构『网摘』-LMLPHP                static private var OperatorMap = new Dictionary<char, OPERATOR> { 
C#: switch语句的重构『网摘』-LMLPHP                        { '+', OPERATOR.Add }, 
C#: switch语句的重构『网摘』-LMLPHP                        { '-', OPERATOR.Minus }, 
C#: switch语句的重构『网摘』-LMLPHP                        { '*', OPERATOR.Divide }, 
C#: switch语句的重构『网摘』-LMLPHP                        { '/', OPERATOR.Multiply }, 
C#: switch语句的重构『网摘』-LMLPHP                };
C#: switch语句的重构『网摘』-LMLPHP                public static OPERATOR GetOperator2(char ch) 
C#: switch语句的重构『网摘』-LMLPHP                { 
C#: switch语句的重构『网摘』-LMLPHP                        if (OperatorMap.ContainsKey(ch)) 
C#: switch语句的重构『网摘』-LMLPHP                                return OperatorMap[ch]; 
C#: switch语句的重构『网摘』-LMLPHP                        else 
C#: switch语句的重构『网摘』-LMLPHP                                return OPERATOR.Unknown; 
C#: switch语句的重构『网摘』-LMLPHP                } 
C#: switch语句的重构『网摘』-LMLPHP        }
这样,不仅代码简洁了很多,而且从本质上已经从逻辑代码维护变成了映射表的维护。
2 动作调用 
接续刚才的例子,这次不仅要实现操作符转化,而且要实现真正的运算。第一个反应又是想到了switch。实现如下:

C#: switch语句的重构『网摘』-LMLPHP     public class Calculator 
C#: switch语句的重构『网摘』-LMLPHP        { 
C#: switch语句的重构『网摘』-LMLPHP                static public int Calculate(char op, int number1, int number2) 
C#: switch语句的重构『网摘』-LMLPHP                { 
C#: switch语句的重构『网摘』-LMLPHP                        int result = 0;
C#: switch语句的重构『网摘』-LMLPHP                        switch (GetOperator(op)) 
C#: switch语句的重构『网摘』-LMLPHP                        { 
C#: switch语句的重构『网摘』-LMLPHP                                case OPERATOR.Add: 
C#: switch语句的重构『网摘』-LMLPHP                                        result = number1 + number2; 
C#: switch语句的重构『网摘』-LMLPHP                                        break; 
C#: switch语句的重构『网摘』-LMLPHP                                case OPERATOR.Minus: 
C#: switch语句的重构『网摘』-LMLPHP                                        result = number1 - number2; 
C#: switch语句的重构『网摘』-LMLPHP                                        break; 
C#: switch语句的重构『网摘』-LMLPHP                                case OPERATOR.Multiply: 
C#: switch语句的重构『网摘』-LMLPHP                                        result = number1 * number2; 
C#: switch语句的重构『网摘』-LMLPHP                                        break; 
C#: switch语句的重构『网摘』-LMLPHP                                case OPERATOR.Divide: 
C#: switch语句的重构『网摘』-LMLPHP                                        result = number1 / number2; 
C#: switch语句的重构『网摘』-LMLPHP                                        break; 
C#: switch语句的重构『网摘』-LMLPHP                                default: 
C#: switch语句的重构『网摘』-LMLPHP                                        throw new Exception("Unsupported Operation!"); 
C#: switch语句的重构『网摘』-LMLPHP                        } 
C#: switch语句的重构『网摘』-LMLPHP                        return result; 
C#: switch语句的重构『网摘』-LMLPHP                } 
C#: switch语句的重构『网摘』-LMLPHP        }
   跟之前遇到的问题有些类似,不过这回需要调用函数。通过.Net环境提供的Dictionary以及Func Delegate的解决如下:

C#: switch语句的重构『网摘』-LMLPHP        public class Calculator 
C#: switch语句的重构『网摘』-LMLPHP        { 
C#: switch语句的重构『网摘』-LMLPHP                static private Dictionary<OPERATOR, Func<int, int, int>> calculationAction = new Dictionary<OPERATOR, Func<int, int, int>> { 
C#: switch语句的重构『网摘』-LMLPHP                        { OPERATOR.Add, Add }, 
C#: switch语句的重构『网摘』-LMLPHP                        { OPERATOR.Minus, Minus }, 
C#: switch语句的重构『网摘』-LMLPHP                        { OPERATOR.Multiply, Multiply }, 
C#: switch语句的重构『网摘』-LMLPHP                        { OPERATOR.Divide, Divide }            
C#: switch语句的重构『网摘』-LMLPHP                };
C#: switch语句的重构『网摘』-LMLPHP                public static OPERATOR GetOperator2(char ch) 
C#: switch语句的重构『网摘』-LMLPHP                { 
C#: switch语句的重构『网摘』-LMLPHP                        if (OperatorMap.ContainsKey(ch)) 
C#: switch语句的重构『网摘』-LMLPHP                                return OperatorMap[ch]; 
C#: switch语句的重构『网摘』-LMLPHP                        else 
C#: switch语句的重构『网摘』-LMLPHP                                return OPERATOR.Unknown; 
C#: switch语句的重构『网摘』-LMLPHP                }
C#: switch语句的重构『网摘』-LMLPHP                static int Add(int number1, int number2) 
C#: switch语句的重构『网摘』-LMLPHP                { 
C#: switch语句的重构『网摘』-LMLPHP                        return number1 + number2; 
C#: switch语句的重构『网摘』-LMLPHP                }
C#: switch语句的重构『网摘』-LMLPHP                // Others are omitted here for brevity 
C#: switch语句的重构『网摘』-LMLPHP        }
通过这个简单的例子,我们可以看出Switch通常会带来一些结构性的重复,通过利用Dictionary等二维表结构,我们可以尽量去避免switch语句,从而实现更好的灵活性和可维护性。最后需要支持的是,在Switch语句的重构过程中需要注意几点:

本文出自 “林家男孩” 博客,请务必保留此出处http://bj007.blog.51cto.com/1701577/345100

05-08 14:48