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

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语句还是要跟着改的,违反了开闭原则。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值