重构—改善代码既有设计 之switch/case使用

原创 2012年03月24日 23:05:29

Switch / Case如下,假设Employee类中有这样两个方法:

PayAmount. 根据员工类型获得员工的薪水:

        public int PayAmount(EmployeeType empType)
        {
            switch (empType)
            {
                case EmployeeType.ENGINEER:
                    return m_basicSalary;
                case EmployeeType.SALESMAN:
                    return m_basicSalary + m_commission;
                case EmployeeType.MANAGER:
                    return 2 * m_basicSalary;
                default:
                    throw new Exception("no such employee type!");
            }
        }

GetDescription. 根据员工类型获得职责描述:

        public string GetDescription(EmployeeType empType)
        {
            switch (empType)
            {
                case EmployeeType.ENGINEER:
                    return "Coding, Debug, Optimization";
                case EmployeeType.SALESMAN:
                    return "Getting contracts";
                case EmployeeType.MANAGER:
                    return "Analysis, Scheduling, Reporting";
                default:
                    throw new Exception("no such employee type!");
            }
        }
这两个方法含有两个几乎一模一样的switch-case语句,如果将来需要增加一种情况,比如“Senior Engineer”那么我们需要去找到这2个方法并分别修改他们。假如一个庞大的系统中有很多这样的方法,改起来就会很麻烦。

现在我们设法将冗余的switch-case语句提炼出来,以期将来需求变化时只需做一次修改即可。

 

 

Solution1 使用简单工厂模式:

为Employee类构造一个简单工厂,能够根据不同的EmployeeType返回相应的子类实例。

        public abstract class Employee
        {
            protected int basicSalary;
            protected int commission;
            public static Employee GetEmployee(EmployeeType empType)
            {
                switch (empType)
                {
                    case EmployeeType.ENGINEER:
                        return new Engineer();
                    case EmployeeType.SALESMAN:
                        return new SalesMan();
                    case EmployeeType.MANAGER:
                        return new Manager();
                    default:
                        throw new Exception("no such employee type!");
                }
            }
            public abstract int PayAmount();
            public abstract string GetDescription();
        }

为switch - case 语句中的不同case分别创建子类,接着将不同case下的逻辑提炼成方法装入相应的子类:

        public class Engineer : Employee
        {
            public override int PayAmount()
            {
                return basicSalary;
            }
            public override string GetDescription()
            {
                return "Coding, Debug, Optimization";
            }
        }
        public class SalesMan : Employee
        {
            public override int PayAmount()
            {
                return basicSalary + commission;
            }
            public override string GetDescription()
            {
                return "Getting contracts";
            }
        }
        public class Manager : Employee
        {
            public override int PayAmount()
            {
                return 2 * basicSalary;
            }
            public override string GetDescription()
            {
                return " Analysis, Scheduling, Reporting ";
            }
        }

 

至此,EmployeeType参数就可以从两个方法中移除了,我们只需在构造Employee对象时指定一次EmployeeType,就能获得想要的Employee行为:

 

        Employee emp = Employee.GetEmployee(EmployeeType.ENGINEER);
        Console.WriteLine(emp.GetDescription());
        Console.WriteLine(emp.PayAmount());

Solution2 使用State模式:


如果一个Employee对象的EmployeeType是可变的(比如一个engineer升职成了manager),那么简单工厂就不适用了。
这种情况下我们可以使用State模式来解决问题,主要做法就是将EmployeType相关的逻辑提炼出来作为独立的一族类,而Employee类将EmployeeType的实例作为自己的一个property,这样,每个Employee的employee type就成为可变的了:

增加一个EmployeeTypeManager类,这个类专门用于描述和EmployeeType相关的行为。

 

    public abstract class EmployeeTypeManager
    {
        public int basicSalary;
        public int commission;
        public abstract int PayAmount();
        public abstract string GetDescription();
    }

我们把Employee子类中和EmployeeType 相关的方法提取到EmployeeTypeManager类的子类中去。省事的做法是直接将之前的Engineer,SalesMan和Manager类声明成EmployeeType的子类 :P

这里,因为这些类只包含一些和EmployeeType相关的行为,而没有自己的状态,所以我们使用了Singleton的实现。此处仅以Engineer类为例说明:

    public class Engineer : EmployeeTypeManager
    {
        private Engineer() { }
        private static Engineer m_Instance;
        public static Engineer Instance
        {
            get
            {
                if (m_Instance == null)
                    m_Instance = new Engineer();
                return m_Instance;
            }
        }
        public override int PayAmount()
        {
            return basicSalary;
        }
        public override string GetDescription()
        {
            return "Coding, Debug, Optimization";
        }
    }

 

接着在Employee类中声明一个EmployeeTypeManager类型的私有成员并为EmployeeType暴露一个property供外界修改:


        private EmployeeTypeManager m_TypeManager;
        public EmployeeType EmpType
        {
            get { return m_type; }
            set { m_type = value; }
        }

将switch-case逻辑从原先的简单工厂挪到EmployeeType的set方法中去:


        public EmployeeType EmpType
        {
            get { return m_type; }
            set
            {
                m_type = value;
                switch (m_type)
                {
                    case EmployeeType.ENGINEER:
                        m_TypeManager = Engineer.Instance;
                        break;
                    case EmployeeType.SALESMAN:
                        m_TypeManager = SalesMan.Instance;
                        break;
                    case EmployeeType.MANAGER:
                        m_TypeManager = Manager.Instance;
                        break;
                    default:
                        throw new Exception("no such employee type!");
                }
            }
        }

最后将对Employee类的两个成员方法的调用委托给EmployeeTypeManager:


        public int PayAmount()
        {
            return m_TypeManager.PayAmount();
        }
        public string GetDescription()
        {
            return m_TypeManager.GetDescription();
        }

Employee类内置的EmployeeTypeManager对象将随着其EmployeeType的改变而改变,从而同一个Employee对象也随之有了不同的行为。

整个过程将各个case的实现逻辑从Employee的子类移到了EmployeeTypeManager及其子类中去,相应的,switch - case判断也被从Employee的简单工厂中移动到了property里。
 

 

重构:运用Java反射加多态 “干掉” switch

前言:本篇文章主要描述我是如何通过Java的反射加多态干掉 swtich这个代码的坏味道 目录 代码的坏味道 《重构》曰 遭遇switch 利剑:多态加反射 结束战斗 代码的坏味道 有这么一句话:...
  • wwh578867817
  • wwh578867817
  • 2015年10月21日 22:08
  • 4878

【重构】使用简单工厂模式重构Switch语句

Code Smell:Switch Statements Switch语句的问题在于,一旦有新case出现,Switch语句块就要加上这条case。如果Switch语句块很多且散布在不同的地方,找到并...
  • weixin_35813749
  • weixin_35813749
  • 2016年12月23日 12:29
  • 1220

用多态重构switch语句

好吧,我这个菜鸟确实是常常在用面向过程的思想在考虑问题,在编写程序。现在我已经摈弃了自己对java语言个人的偏见,而是用平等公平的态度看待java和C++。他们各有千秋,各有乾坤的。 好吧,入正题。...
  • pty_2007
  • pty_2007
  • 2012年10月06日 10:46
  • 2583

使用注解加反射去除switch重构代码

这星期碰到了需要对switch代码进行重构,这个我是在解析request时碰到的情况,今天记录下来。 废话不多说,先上选来的代码 public class Main { public st...
  • itslz
  • itslz
  • 2017年04月22日 22:26
  • 233

利用策略枚举对讨厌的Switch Case 语句进行重构

本文中介绍如何利用策略枚举对讨厌的Switch Case 语句进行重构,不仅更简洁,而且性能更好。...
  • timchen525
  • timchen525
  • 2017年07月14日 00:39
  • 351

重构:switch语句改成策略模式还是状态模式

在重构篇里,可以用多态来取代switch语句,但是因为:一部影片可以在生命周期内修改自己的分类,一个对象却不能在生命周期内修改自己所属的类。所以这里不能用策略模式,用多态取代switch,而应该用状态...
  • qq_21381465
  • qq_21381465
  • 2016年05月02日 22:32
  • 1945

解决switch 多case问题的方法之一

   当switch 有很多情况要判断的时候,代码会很长很难看,而且是违反面向对象思想的。如果每个情况触发的都是由继承自同一个基类或实现同一个接口的话。如:abstract  class A{   p...
  • silywiwi
  • silywiwi
  • 2007年08月15日 15:56
  • 592

switch多个case执行一段代码

switch多个case执行一段代码
  • diyu122222
  • diyu122222
  • 2017年06月15日 11:47
  • 176

C语言优化实例:一种消除嵌套switch-case的巧妙做法

我们有可能会写出或者遇到类似这样的代码: C/C++ switch (expr1) { case label11: switch (expr2) ...
  • chfe007
  • chfe007
  • 2014年10月30日 10:25
  • 3679

如何干掉那又丑又长的switch..case语句

1、前言     在实际的编程中,我们经常会使用到switch..case语句,这通常也是对一长串if..else if语句的优化。对于一些简单的情况(只每个case代码中代码长度不会很长,而且ca...
  • acaiwlj
  • acaiwlj
  • 2015年10月27日 09:41
  • 2878
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:重构—改善代码既有设计 之switch/case使用
举报原因:
原因补充:

(最多只允许输入30个字)