脑图
类型码
(1) `不会出现在 条件语句(switch/if)中` 而影响类的行为
重构 1: Replace Type Code with Class
(2) else
应该
1) 先`去掉 类型码`
[1] if
1] `Type Code 宿主类 没有子类`, 或
2] `类型码 在对象创建后 不会改变`
重构 2: Relpace Type Code with Subclass
| |
| |/
| 重构 4: `对 创建对象的 switch 用 Relpace Ctor with Factory Method`
| |
|/ |/
重构 5: `Replace Conditional with polymorphism` => 跳过后续 2)
[2] if
1] `Type Code 宿主类 有子类`, 或
2] `类型码 在对象创建后 会改变`
重构 3: Relpace Type Code with State/Strategy
| | | 类型码 field 换为 新类的指针 EmployeeType*`
| | |
| | |/
| | 重构 4
| | |
| |/ |/
| 重构 5
|/
重构 6: 将 `类型码 info(类型码枚举值/编译期常量 ENGINEER / MANAGER)`
和 `子类(Engineer / Manager) info` 均移到 新类 EmployeeType
2) 再`用 vf/多态 取代 条件语句`
重构 5: Replace Conditional with Ploymorphism
好处: `把 "对不同行为的了解" 从类的用户转移到类自身.
若需要新增新的行为变化, 只需要增加1个子类即可.`
若无多态机制, 就必须找到所有条件语句, 修改
3) 将`只与特定子类相关`的 `字段和函数 下推`到相关子类
重构 7: Push Down Field & Method
1 Replace Type Code with Class
动机
类含 (数值)`Type Code/枚举值` -> `不能` 实现 `编译器/运行期 类型检查` -> `bug 之源`
前提
`Type Code` 是 纯粹数据, `不会出现在条件语句(switch/if)中而影响类的行为`
做法
Type Code -> Type Code 类, 可实现 运行期 类型检查
类型码原宿主类
[1] 类型码字段(field) 改用 新类(类型码类) objPtr,
[2] Ctor / 设值函数 / 取值函数 的 para或returnValue 改用 新类(Ptr)
新类(类型码类)
[1] Note1: `创建静态对象用工厂函数, 保证了只有合法的 静态对象 才会被创建`
[2] `一组静态变量` 保存允许被创建的 object
———————————————————————————————————————
| Person |
———————————————————————————————————————
| + O: static int ——| —— —— = 0
| + A: static int ——| —— —— = 1
| |
| - bloodType: int |
———————————————————————————————————————
| + Person(int bloodType_) |
| + setBloodType(int bloodType_):void |
| + getBloodType(): int |
————————————————————————————————————————
|
| 重构 1
|/
———————————————————————————————————————————— ————————————————————————————————————————————————————
| Person | \ | BloodType |
———————————————————————————————————————————— ————— —————————————————————————————————————————————————————
| - bloodType: BloodType* | / | + O: static BloodType* |
———————————————————————————————————————————— | + A: static BloodType* |
| + Person(BloodType* bloodType_) | | |
| + setBloodType(BloodType* bloodType_) | | - typeCode: int |
| + getBloodType(): BloodType* | | - bloodTypeVec: static vector<BloodType*> |
———————————————————————————————————————————— ————————————————————————————————————————————————————
| + BloodType(int typeCode_) |
| |
| - getBloodType(int typeCode_): static BloodType* |
| - getTypeCode() : int |
————————————————————————————————————————————————————
`工厂函数, 保证了只有合法 静态对象 才会被创建`
BloodType* BloodType::O = new BloodType(0);
static vector<BloodType> bloodTypeVec = {O, A}
Client // #include "Person.h"
Person* person = new Person(BloodType::A);
BloodType* bloodType = person->getBloodType();
person->setBloodType(BloodType::O);
2 Replace Type Code with SubClass
动机
类 中 type code 为 数值, 影响 类 的 行为(据 不同 type code 执行 不同动作)
做法
以 多态 处理 变化
Replace Type Code with SubClass
以 type code 宿主类 为 Base 类, 对 每种 type code 建相应 Derived 类
+
Replace Conditional with Polymorphism
———————————————————————————————————————
| Employee |
————————————————————————————————————————
| - typeCode: int |
| - monthlySalary |
| - bonus |
| |
| + ENGINEER: static const int = 0 |
| + MANAGER: static const int = 1 |
———————————————————————————————————————
| + Employee(int typeCode_) |
| |
| + payAmount(): int - -| - - switch (typeCode)
———————————————————————————————————————
Client
pEmployee = new Employee(Employee::ENGINEER);
pEmployee->payAmount();
Step1 类型码替换为子类 + Ctor 替换为工厂方法(Refactor2+Refactor4)
基类
(1) 去掉 类型码 field
=> 所有 non-vf
: (新增)静态工厂方法 + 其他 non-vf
(即 条件函数
) 如何知道各子类对象的类型码 ? -> 类型码 形参
=> 条件函数
的 类型码实参
-> 用 新增 获取子类类型码 的 vf 的调用
(2) 去掉 Ctor + 新增 静态工厂方法
————————————————————————————————————————————
| Employee |
—————————————————————————————————————————————
| - monthlySalary |
| - bonus |
| |
| + ENGINEER: static int = 0 |
| + MANAGER: static int = 1 |
———————————————————————————————————————————— // switch 只在 创建 对象 时有
| + create(int typeCode_): static Employee* | - - switch (typeCode_) { case ENGINEER: return new Engineer(); // ... }
| |
| + payAmount(int typeCode_): int - - | - - switch (typeCode_) { case ENGINEER: return monthlySalary; // ... }
| |
| + getTypeCode(): virtual int = 0 |
————————————————————————————————————————————
/\
/__\
| |
| |_ _ _ _ _ _ _
| |
———————————————————————— ————————————————————————
| Engineer | | Manager |
———————————————————————— ————————————————————————
| | | |
———————————————————————— ————————————————————————
| + getTypeCode(): int | | + getTypeCode(): int |
—————|——————————————————— —————|———————————————————
| |
return Employee::ENGINEER; return Employee::MANAGER;
Client:
Employee* pEmployee = Employee::create(Employee::ENGINEER);
pEmployee->payAmount(pEmployee->getTypeCode() );
Step2 条件函数换为 多态
(1) 条件函数
由 non-vf 换成 vf
=>
[1] vf 不再需要 类型码形参
(虚调用机制 子类用自己的 type_info 告诉自己的 类型码
) => 条件函数不再需要 类型码实参
=> 类层次 不再需要 获取子类类型码的 vf
[2] vf 内需要 获取 基类的成员
=> 基类 新增 get 函数
————————————————————————————————————————————
| Employee |
—————————————————————————————————————————————
| - monthlySalary |
| - bonus |
| |
| + ENGINEER: constexpr int = 0 |
| + MANAGER: constexpr int = 1 |
————————————————————————————————————————————
| + create(int typeCode_): static Employee* |
| |
| + payAmount(int typeCode_): virtual int=0 |
| + getMonthlySalary(): int |
| + getBonus(): int |
————————————————————————————————————————————
/\
/__\
| |
| |_ _ _ _ _ _ _ _ _ _ _ _ _
| |
——————————————————————————————— ———————————————————————————————
| Engineer | | Manager |
——————————————————————————————— ———————————————————————————————
| | | |
——————————————————————————————— ———————————————————————————————
| + payAmount(): virtual int | | + payAmount(): virtual int |
———————|———————————————————————— ——————-|—————————————————————————
| |
return getMonthlySalary(); return getMonthlySalary() + getBonus();
Client:
Employee* pEmployee = Employee::create(Employee::ENGINEER);
pEmployee->payAmount();
Step3 Push Down Field & Method: 将只与特定子类相关
的字段和函数下推
到相关子类
只变动4个文件: Employee.h/cpp Manager.h/cpp
————————————————————————————————————————————
| Employee |
—————————————————————————————————————————————
| - monthlySalary |
| |
| + ENGINEER: constexpr int = 0 |
| + MANAGER: constexpr int = 1 |
————————————————————————————————————————————
| + create(int typeCode_): static Employee* |
| |
| + payAmount(int typeCode_): virtual int=0 |
| |
| + getMonthlySalary(): int |
————————————————————————————————————————————
/\
/__\
| |
| |_ _ _ _ _ _ _ _ _ _ _ _ _
| |
——————————————————————————————— ———————————————————————————————
| Engineer | | Manager |
——————————————————————————————— ———————————————————————————————
| | | - bonus | |
——————————————————————————————— ———————————————————————————————
| | | + getBonus(): int |
| + payAmount(): virtual int | | + payAmount(): virtual int |
———————|———————————————————————— ——————-|—————————————————————————
| |
return getMonthlySalary(); return getMonthlySalary() + getBonus();
3 Replace Type Code with Sate/Strategy
动机
`type code 可变` => 不能用 继承 消除它
做法
type code 替换为 状态对象
类型码可变 =>
(1) 需要1个 设置 类型码的函数 setType(typeCode_)
: 只修改类型码
(2) 条件函数
中无需类型码参数, switch 中
放的固定类型码
换为 获取类型码的函数 getType() 的调用
———————————————————————————————————————
| Employee |
————————————————————————————————————————
| - type: int |
| - monthlySalary |
| - bonus |
| |
| + ENGINEER: static constexpr int = 0 |
| + MANAGER: static constexpr int = 1 |
———————————————————————————————————————
| + Employee(int typeCode_) |
| |
| + payAmount(): int - -| - - switch (getType() ) // typeCode can be change
| + getType(): int |
| |
| + setType(int typeCode_): void - -| - - type = typeCode_;
———————————————————————————————————————
Client
pEmployee = new Employee(Employee::ENGINEER);
pEmployee->payAmount();
pEmployee->setType(Employee::MANAGER);
pEmployee->payAmount();
Step1: 类型码 field 换为 新类的指针 EmployeeType*
(重构 3)
(1) 新建1个类型码类
[1] 其指针
放 原类型码所属类 -> Composition
[2] 只放1个 获取子类类型码的 vf
[3] 再新建其 子类
(2) 设置 类型码的函数 setType(typeCode_):
(重)建 子类对象
: new 子类对象 + 赋值给 类型码类指针
[1] 被 Ctor
调用, 初建
[2] 被 Client
调用, 重建
(3) 原类 获取类型码的函数 getType() (non-vf) 转调
类型码类层次的 获取类型码的函数 getTypeCode() (vf)
———————————————————————————————————————
| Employee | ————————————————————————————————————
———————————————————————————————————————— | EmployeeType |
| - type: EmployeeType* | \ ————————————————————————————————————
| - monthlySalary | ———————————— | |
| - bonus | / ————————————————————————————————————
| | | + getTypeCode():virtual int = 0 |
| + ENGINEER: static constexpr int = 0 | ————————————————————————————————————
| + MANAGER: static constexpr int = 1 | \ /\
——————————————————————————————————————— \ /__\
| + Employee(int typeCode_) | \ | add 子类: 每个子类对应1种 type
| + setType(int typeCode_): void | \ |
| | | \ include ———————————————————————————————
- - | + payAmount(): int | | \- - - - - ->| Engineer |
| | + getType(): int | | | ———————————————————————————————
| ———————|———————————————|———————————————— | | |
| | | | ———————————————————————————————
| | switch (typeCode_) | | + getTypeCode(): virtual int |
| | case ENGINEER: | ——————————|—————————————————————
| | type = new Engineer(); ; |
| type->getTypeCode(); break return Employee::ENGINEER
|
|- - switch (getType() )
Step2: 将 类型码 info
(类型码枚举值/编译期常量 ENGINEER / MANAGER) 移到 类型码类 EmployeeType
(重构 6)
(1) 类型码常量 移动
=> 条件函数中 case 类型码常量
换为 case 类型码类::类型码常量
(2) 原类 setType()
中 条件 (重)建(new)子类对象/Ctor
换为 转调用 类型码类的 工厂函数
——————————————————————————————————————— ———————————————————————————————————————————————
| Employee | | EmployeeType |
———————————————————————————————————————— ———————————————————————————————————————————————
| - type: EmployeeType* | \ | + ENGINEER: static constexpr int = 0 |
| - monthlySalary | ———————————— | + MANAGER: static constexpr int = 1 |
| - bonus | / ———————————————————————————————————————————————
——————————————————————————————————————— - - - - - ->| + newType(int typeCode): static EmployeeType* | - - switch (typeCode_)
| + Employee(int typeCode_) | | | | case ENGINEER:
| + setType(int typeCode_): void | | - ->| + getTypeCode(): virtual int = 0 | return new Engineer();
| | | | | —————————————————————————————————————————————————
- - | + payAmount(): int | | | | /\
| | + getType(): int | | | | /__\
| ———————|———————————————|———————————————— | | |
| | | | | |
| | type = EmployeeType::newType(typeCode_); | ———————————————————————————————
| | | | Engineer |
| | | ———————————————————————————————
| type->getTypeCode(); - - - - - - - - - - - - - - | |
| ———————————————————————————————
|- - switch (getType() ) | + getTypeCode(): virtual int |
case EmployeeType::ENGINEER: ——————————|—————————————————————
return monthlySalary; |
return Employee::ENGINEER
Step3: 原类的 条件函数(non-vf) 转调
类型码类中新增
的相应 多态 vf
(1) 后者想获取前者中的 成员数据
=> 通过前者的 成员函数
=> 需要拿到 原类对象的指针 => 前者转调后者时, 以自身对象的指针 this 作实参
=>
[1] 原类要新增 getFunc()
[2] 原类/新类 getType()/getTypeCode() 均不再需要
(2) 新类不 include(而是 前向声明)原宿主类
, 具体子类(Engineer.h) include(依赖)新类(EmployeeType.h) 和原宿主类(Employee.h), 但
——————————————————————————————————————— ———————————————————————————————————————————————————
| Employee | | EmployeeType |
———————————————————————————————————————— ———————————————————————————————————————————————————
| - type: EmployeeType* | \ | + ENGINEER: static constexpr int = 0 |
| - monthlySalary | ———————————— | + MANAGER: static constexpr int = 1 |
| - bonus | / ———————————————————————————————————————————————————
——————————————————————————————————————— - - - - - ->| + newType(int typeCode): static EmployeeType* | - - switch (typeCode_)
| + Employee(int typeCode_) | | | | case ENGINEER:
| + setType(int typeCode_): void | | |-->| + payAmount(Employee* pEmployee):virtual int = 0 | return new Engineer();
| | | | | ————————————————————————————————————————————————————
| + payAmount(): int | | | | /\
| | | | | | /__\
- ->| + getMonthlySalary(): | int | | | |
| ———————|———————————————|———————————————— | | |
| /|\ | | | | |
| | | type = EmployeeType::newType(typeCode_); | ———————————————————————————————————————————————
| | | | | Engineer |
| | | | ———————————————————————————————————————————————
| | return type->payAmount(this); - - - - - - - - - - | |
| | ———————————————————————————————————————————————
| |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - | + payAmount(Employee* pEmployee): virtual int |
| #include(依赖) ——————————|————————————————————— ————————————————
| |
| |
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - return pEmployee->getMonthlySalary();
Step4: Push Down Field & Method (重构 7)
方法同 2.3
网友评论