《重构:改善既有代码的设计》中提到过很多重构方法,关于重新组织数据的方法有16种。本文介绍:
以子类取代类型码 replace type code with subclasses
- 名称:以子类取代类型码 replace type code with subclasses
- 概要:有一个不可变的类型码,它会影响类的行为。以子类取代这个类型码
- 动机:如果类型码不会影响宿主类的行为,可以使用replace type code with class来处理。如果影响,就要借助多态来处理变化行为。
- 做法:
- 使用self encapsulate field将类型码自我封装起来。如果类型码被传递给构造函数,就需要将构造函数换成工厂函数。
- 为类型码的每一个数值建立一个相应的子类。在每个子类中覆写类型码的取值函数,使其返回相应的类型码值。
- 每建立一个新的子类,编译并测试
- 从超类中删掉保存类型码的字段,将类型码访问函数声明为抽象函数
- 编译,测试
- 代码演示
修改之前的代码:
/.h
class Employee
{
public:
Employee(int code);
static const int ENGINEER;
static const int SALESMAN;
static const int MANAGER;
private:
int m_code;
};
//.cpp
const int Employee::ENGINEER = 0;
const int Employee::SALESMAN = 1;
const int Employee::MANAGER = 2;
Employee::Employee(int code)
{
m_code = code;
}
/main.cpp
Employee engineer(Employee::ENGINEER);
qDebug() << "employee code = " <<engineer.getCode();
1) 以self encapsulate field将 m_code自我封装起来
2)将employee的构造函数替换为一个工厂函数
3)先建立一个子类Engineer表示工程师,并覆写类型码取值函数
4)修改工厂函数,令它返回一个合适的对象
5)处理其他的类型码,将gettype设置为纯虚函数。
这样之后,客户调用就不会使用类型码了
修改之后的代码:
/.h
class Employee
{
public:
Employee(int code);
static Employee* create(int code);
static const int ENGINEER;
static const int SALESMAN;
static const int MANAGER;
virtual int getCode() = 0;
private:
int m_code;
};
class Engineer : public Employee
{
public:
Engineer();
int getCode();
};
class Salesman : public Employee
{
public:
Salesman();
int getCode();
};
class Manager : public Employee
{
public:
Manager();
int getCode();
};
class Error : public Employee
{
public:
Error();
int getCode();
};
//.cpp
const int Employee::ENGINEER = 0;
const int Employee::SALESMAN = 1;
const int Employee::MANAGER = 2;
Employee::Employee(int code)
{
m_code = code;
}
Employee *Employee::create(int code)
{
switch (code) {
case ENGINEER:
return new Engineer();
case SALESMAN:
return new Salesman();
case MANAGER:
return new Manager();
default:
//throw Except
return new Error();
}
}
Engineer::Engineer():Employee (ENGINEER)
{
}
int Engineer::getCode()
{
return ENGINEER;
}
Salesman::Salesman():Employee (SALESMAN)
{
}
int Salesman::getCode()
{
return SALESMAN;
}
Manager::Manager():Employee (MANAGER)
{
}
int Manager::getCode()
{
return MANAGER;
}
Error::Error():Employee (MANAGER)
{
}
int Error::getCode()
{
return MANAGER;
}
/main.cpp
Employee *engineer = new Engineer;
qDebug() << "employee code = " <<engineer->getCode();