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

来源:互联网 发布:oracle数据库语法 编辑:程序博客网 时间:2024/06/03 13:21

Code Smell:Switch Statements

Switch语句的问题在于,一旦有新case出现,Switch语句块就要加上这条case。

如果Switch语句块很多且散布在不同的地方,找到并修改它们将是非常恐怖的事。

下面这个例子是,根据枚举中employee的角色,
GetDescription(EmployeeType empType)方法给出employee的职位描述;
PayAmount(EmployeeType empType)方法给出employee的薪酬。

如果这个时候我在枚举中添加另一个角色:consultant。
那么我就要找到上面两个方法,把case consultant的判断语句加到原来的switch语句中。

而简单工厂模式重构的意义在于:不用再去找涉及新角色的switch语句,把角色应有的属性和方法直接写在该角色所在的类中。

package refraction.swith;public class BeforeRefraction {     enum EmployeeType{        ENGINEER,SALESMAN,MANAGER;     }     public static int m_basicSalary;     public static int m_commission;     /**     *      * switch语句接收枚举类型,判断输出相应的薪资算法     * @param empType    Employee type in enum     * @return           Payment of each type     */     public int PayAmount(EmployeeType empType) throws Exception     {         switch (empType)         {             case ENGINEER:                 return m_basicSalary;             case SALESMAN:                 return m_basicSalary + m_commission;             case MANAGER:                 return 2 * m_basicSalary;             default:                 throw new Exception("no such employee type!");         }     }     /**     * switch再来一遍,接收枚举类型,判断输出相应的职位描述     *      * @param empType    Employee type in enum     * @return           Description of each type     */     public String GetDescription(EmployeeType empType) throws Exception     {         switch (empType)         {             case ENGINEER:                 return "Coding, Debug, Optimization";             case SALESMAN:                 return "Getting contracts";             case MANAGER:                 return "Analysis, Scheduling, Reporting";             default:                 throw new Exception("no such employee type!");         }}}

多态是面向对象编程的精髓之一,我们来回顾多态的要点:
1.接口/抽象类的引用变量可以引用实现类的对象
2.父类的引用变量可以引用子类的对象
3.实现类需要重写抽象方法

基于多态的理念,我们
第一步:把case中的角色抽象成继承了(实现了)统一抽象类(接口)的子类。
第二步:子类实现各自的抽象方法
第三步:工厂根据定制,按需创建子类的对象。

STEP1
把Switch语句中的每个case抽取出来:

  • class Engineer
  • class Salesman
  • class Manager

STEP2
然后把他们共有的部分抽象为一个抽象类或者接口:

  • abstract class Employee

STEP3
工厂接收抽象类或接口的引用变量,再根据引用变量的类型按条件new出具体的子类。工厂可以是一个单独的类,也可以是放在上面的抽象类中。

这里写图片描述

package refraction.swith;public class AfterRefraction {    public static void main(String[] args) {        Employee employee = null;        try {            employee = Factory.getEmployee(EmployeeType.ENGINEER);        } catch (Exception e) {            e.printStackTrace();        }        employee.getDescription();        System.out.println("Salary:"+employee.PayAmount());    }}enum EmployeeType{    ENGINEER,SALESMAN,MANAGER; }abstract class Employee{    public static int m_basicSalary;    public static int m_commission;    /*    * 工厂方法也可以放在这里,仍然是一个静态方法    */    public abstract String getDescription();    public abstract int PayAmount();}//把Switch语句中的每个case抽取出来,然后把他们共有的部分抽象为一个抽象类或者class Engineer extends Employee{    @Override    public String getDescription() {        return "Coding, Debug, Optimization";    }    @Override    public int PayAmount() {        return  m_basicSalary;    }}class Salesman extends Employee{    @Override    public String getDescription() {        return "Getting contracts";    }    @Override    public int PayAmount() {        return  m_basicSalary + m_commission;    }}class Manager extends Employee{    @Override    public String getDescription() {        return "Analysis, Scheduling, Reporting";    }    @Override    public int PayAmount() {        return  m_basicSalary *2;    }}/*** * 工厂类,这里只有一个静态方法* 工厂类只做一件事:按条件new对象* 这样一来,我们在main方法中就不用new不同的employee对象了*/class Factory{    public static Employee getEmployee(EmployeeType employee) throws Exception{        switch(employee){            case ENGINEER:                return new Engineer();            case SALESMAN:                return new Salesman();            case MANAGER:                return new Manager();            default:                throw new Exception("no such employee type!");        }    }}

简单工厂模式的缺陷:
1.甲方必须知道工厂能产出什么,否则工厂要抛出异常。
2.新增了case后,虽然不用再去找散落各处的switch语句,但是工厂中的switch语句还是要跟着改的,违反了开闭原则。

1 0
原创粉丝点击