• 使用简单工厂和State模式替换冗余的 switchcase 语句


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

    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里。

        

     

     

     

  • 相关阅读:
    《Windows程序设计》中未归类的API
    C++编程技巧亮点集结
    详解python实现FPTREE进行关联规则挖掘(带有FP树显示功能)附源代码下载(5)
    python源码剖析 读书笔记
    python操作时间的几个重要函数总结 import time!
    判断关联规则是否可靠提升度 lift,KULC,IR
    详解python实现FPTREE进行关联规则挖掘(带有FP树显示功能)附源代码下载(3)
    python 使用装饰器模式 保证带有默认值的参数不被修改默认值
    python open文件 读写模式说明
    详解python实现FPTREE进行关联规则挖掘(带有FP树显示功能)附源代码下载(4)
  • 原文地址:https://www.cnblogs.com/k330/p/1137779.html
Copyright © 2020-2023  润新知