您的位置:首页 > 其它

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

2016-12-23 12:29 316 查看
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语句还是要跟着改的,违反了开闭原则。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐