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