首页 > 其他 > 详细

使用简单工厂和State模式替换冗余的 switch-case 语句

时间:2014-03-04 11:01:24      阅读:595      评论:0      收藏:0      [点我收藏+]

使用简单工厂和State模式替换冗余的 switch-case 语句

         这篇曾经贴在自己的live space上,今天整理出来发在这里。 内容参考了《重构》《设计模式》

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

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

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

bubuko.com,布布扣        }


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

bubuko.com,布布扣        public string GetDescription(EmployeeType empType)
bubuko.com,布布扣        {
bubuko.com,布布扣            switch (empType)
bubuko.com,布布扣            {
bubuko.com,布布扣                case EmployeeType.ENGINEER:
bubuko.com,布布扣                    return "Coding, Debug, Optimization";
bubuko.com,布布扣                case EmployeeType.SALESMAN:
bubuko.com,布布扣                    return "Getting contracts";
bubuko.com,布布扣                case EmployeeType.MANAGER:
bubuko.com,布布扣                    return "Analysis, Scheduling, Reporting";
bubuko.com,布布扣                default:
bubuko.com,布布扣                    throw new Exception("no such employee type!");
bubuko.com,布布扣            }

bubuko.com,布布扣        }

这两个方法含有两个几乎一模一样的switch-case语句,如果将来需要增加一种情况,比如“Senior Engineer”那么我们需要去找到这2个方法并分别修改他们。假如一个庞大的系统中有很多这样的方法,改起来就会很麻烦。

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

 

 

 

 

Solution1 使用简单工厂模式:

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

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

bubuko.com,布布扣            }

bubuko.com,布布扣            public abstract int PayAmount();
bubuko.com,布布扣            public abstract string GetDescription();
bubuko.com,布布扣        }


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

bubuko.com,布布扣        public class Engineer : Employee
bubuko.com,布布扣        {
bubuko.com,布布扣            public override int PayAmount()
bubuko.com,布布扣            {
bubuko.com,布布扣                return basicSalary;
bubuko.com,布布扣            }

bubuko.com,布布扣            public override string GetDescription()
bubuko.com,布布扣            {
bubuko.com,布布扣                return "Coding, Debug, Optimization";
bubuko.com,布布扣            }

bubuko.com,布布扣        }

bubuko.com,布布扣        public class SalesMan : Employee
bubuko.com,布布扣        {
bubuko.com,布布扣            public override int PayAmount()
bubuko.com,布布扣            {
bubuko.com,布布扣                return basicSalary + commission;
bubuko.com,布布扣            }

bubuko.com,布布扣            public override string GetDescription()
bubuko.com,布布扣            {
bubuko.com,布布扣                return "Getting contracts";
bubuko.com,布布扣            }

bubuko.com,布布扣        }

bubuko.com,布布扣        public class Manager : Employee
bubuko.com,布布扣        {
bubuko.com,布布扣            public override int PayAmount()
bubuko.com,布布扣            {
bubuko.com,布布扣                return 2 * basicSalary;
bubuko.com,布布扣            }

bubuko.com,布布扣            public override string GetDescription()
bubuko.com,布布扣            {
bubuko.com,布布扣                return " Analysis, Scheduling, Reporting ";
bubuko.com,布布扣            }

bubuko.com,布布扣        }

 

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

bubuko.com,布布扣        Employee emp = Employee.GetEmployee(EmployeeType.ENGINEER);
bubuko.com,布布扣        Console.WriteLine(emp.GetDescription());
bubuko.com,布布扣        Console.WriteLine(emp.PayAmount());
bubuko.com,布布扣


 

Solution2 使用State模式:

 

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

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

 

bubuko.com,布布扣    public abstract class EmployeeTypeManager
bubuko.com,布布扣    {
bubuko.com,布布扣        public int basicSalary;
bubuko.com,布布扣        public int commission;
bubuko.com,布布扣        public abstract int PayAmount();
bubuko.com,布布扣        public abstract string GetDescription();
bubuko.com,布布扣    }

bubuko.com,布布扣


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

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

bubuko.com,布布扣    public class Engineer : EmployeeTypeManager
bubuko.com,布布扣    {
bubuko.com,布布扣        private Engineer() { }
bubuko.com,布布扣        private static Engineer m_Instance;
bubuko.com,布布扣        public static Engineer Instance
bubuko.com,布布扣        {
bubuko.com,布布扣            get
bubuko.com,布布扣            {
bubuko.com,布布扣                if (m_Instance == null)
bubuko.com,布布扣                    m_Instance = new Engineer();
bubuko.com,布布扣                return m_Instance;
bubuko.com,布布扣            }

bubuko.com,布布扣        }

bubuko.com,布布扣        public override int PayAmount()
bubuko.com,布布扣        {
bubuko.com,布布扣            return basicSalary;
bubuko.com,布布扣        }

bubuko.com,布布扣        public override string GetDescription()
bubuko.com,布布扣        {
bubuko.com,布布扣            return "Coding, Debug, Optimization";
bubuko.com,布布扣        }

bubuko.com,布布扣    }

 

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

bubuko.com,布布扣        private EmployeeTypeManager m_TypeManager;
bubuko.com,布布扣        public EmployeeType EmpType
bubuko.com,布布扣        {
bubuko.com,布布扣            get return m_type; }
bubuko.com,布布扣            set { m_type = value; }
bubuko.com,布布扣        }

bubuko.com,布布扣

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

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

bubuko.com,布布扣            }

bubuko.com,布布扣        }

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

bubuko.com,布布扣        public int PayAmount()
bubuko.com,布布扣        {
bubuko.com,布布扣            return m_TypeManager.PayAmount();
bubuko.com,布布扣        }

bubuko.com,布布扣        public string GetDescription()
bubuko.com,布布扣        {
bubuko.com,布布扣            return m_TypeManager.GetDescription();
bubuko.com,布布扣        }

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

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

使用简单工厂和State模式替换冗余的 switch-case 语句,布布扣,bubuko.com

使用简单工厂和State模式替换冗余的 switch-case 语句

原文:http://www.cnblogs.com/sy88/p/3578890.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!