美文网首页
重构-Type Code / 条件语句 / vf 多态: C++

重构-Type Code / 条件语句 / vf 多态: C++

作者: my_passion | 来源:发表于2022-09-18 23:38 被阅读0次

1 Replace Type Code with Class

1.0 重构前

// Person.h
#pragma once

class Person
{
public:
    static int O;
    static int A;
private:
    int bloodType;
public:
    Person(int bloodType_);
    void setBloodType(int bloodType_);
    int getBloodType();
};
// Person.cpp
#include "Person.h"

int Person::O = 0; // Note: static var/func 定义处不能再用 static  
int Person::A = 1;

Person::Person(int bloodType_)
    : bloodType(bloodType_) {}

void Person::setBloodType(int bloodType_)
{
    bloodType = bloodType_;
}
int Person::getBloodType()
{
    return bloodType;
}
// main.cpp 
#include "Person.h"

int main()
{
    Person* person = new Person(Person::A);

    int bloodType = person->getBloodType();

    person->setBloodType(Person::O);
}

1.1 重构 1

// Person.h
#pragma once

#include "BloodType.h"

class Person
{
private:
    BloodType* bloodType;
public:
    Person(BloodType* bloodType_);
    
    void setBloodType(BloodType* bloodType_);

    BloodType* getBloodType();
    ~Person();
};
// BloodType.h
#pragma once

#include <vector>

class BloodType
{
public:
    // (1) Note1: 创建静态对象用工厂函数, 保证了只有合法的 静态对象 才会被创建
    static BloodType* O;
    static BloodType* A;
private:
    int typeCode;
public:
    BloodType(int typeCode_);
    
private: // (2) Note2: Client not use
    // (3) 一组静态变量 保存允许被创建的 object 
    static std::vector<BloodType*> bloodTypeVec;
    
    // (4) 取一组静态变量中的1个, 对应用静态函数
    static BloodType* getBloodType(int typeCode_);
    
    int getTypeCode();
};

void destoryGlobal();
// Person.cpp
#include "Person.h"

Person::Person(BloodType* bloodType_)
    : bloodType(bloodType_) {}

void Person::setBloodType(BloodType* bloodType_)
{
    bloodType = bloodType_;
}

BloodType* Person::getBloodType()
{
    return bloodType;
}

Person::~Person()
{
    bloodType = nullptr; // (5) Note3: 静态对象的释放 由 client 最后全局处理
}
// BloodType.cpp
#include "BloodType.h"

BloodType* BloodType::O = new BloodType(0);
BloodType* BloodType::A = new BloodType(1);

std::vector<BloodType*> BloodType::bloodTypeVec =
{ O, A };

BloodType::BloodType(int typeCode_)
    : typeCode(typeCode_) { }

BloodType* 
BloodType::getBloodType(int typeCode_)
{
    return bloodTypeVec[typeCode_];
}

int BloodType::getTypeCode()
{
    return typeCode;
}

void destoryGlobal()
{
    if (BloodType::O)
    {
        delete BloodType::O;
        BloodType::O = nullptr;
    }
        
    if (BloodType::A)
    {
        delete BloodType::A;
        BloodType::A = nullptr;
    }
}
// main.cpp
#include "Person.h"

int main()
{
    Person* person = new Person(BloodType::A);

    BloodType* bloodType = person->getBloodType();

    person->setBloodType(BloodType::O);

    if (person)
        delete person;
    destoryGlobal();
}

2 Relpace Type Code with Subclass

2.0 重构前

// Employee.h
#pragma once

class Employee
{
private:
    int typeCode;
    int monthlySalary;
    int bonus; // only Manager has 
public:
    static const int ENGINEER;
    static const int MANAGER;
public:
    Employee(int typeCode_);
    int payAmount();
};
// Employee.cpp
#include "Employee.h"
#include <iostream>

const int Employee::ENGINEER = 0;
const int Employee::MANAGER = 1;

Employee::Employee(int typeCode_)
    :typeCode(typeCode_), monthlySalary(20000), bonus(10000) {}

int Employee::payAmount()
{
    switch (typeCode) // Note: typeCode doesn't changed
    {
    case ENGINEER:
        return monthlySalary;
    case MANAGER:
        return monthlySalary + bonus;
    default:
        return 0;
    }
}
// main.cpp
#include "Employee.h"

int main()
{
    Employee* pEmployee = new Employee(Employee::ENGINEER);
    int pay = pEmployee->payAmount();
    delete pEmployee;

    pEmployee = new Employee(Employee::MANAGER);
    pay = pEmployee->payAmount();
    delete pEmployee;
    pEmployee = nullptr;
}

2.1 step1-Refactor2+Refactor4

// Employee.h
#pragma once

class Employee
{
private:
    // (1) Note1: remove TypeCode field
    int monthlySalary;
    int bonus; // only Manager has 
public:
    static constexpr int ENGINEER = 0;
    static constexpr int MANAGER = 1;
public:
    Employee();
    
    // (2) Note2: Refactor4- Relpace Ctor with Factory Method
    static Employee* create(int typeCode_);

    // (3) Note3: Conditional func add typeCodePara
    int payAmount(int typeCode_); // arg = getTypeCode()
    
    // (4) Note4: Let Subclass tell its typeCode
    virtual int getTypeCode() = 0;
};
// Engineer.h
#pragma once
#include "Employee.h"

class Engineer: public Employee
{
public:
    int getTypeCode();
};
// Manager.h
#pragma once
#include "Employee.h"

class Manager: public Employee
{
public:
    int getTypeCode();
};
// EmployeeFactor.cpp
#include "Employee.h"
#include "Engineer.h"
#include "Manager.h"

Employee*
Employee::create(int typeCode_)
{
    switch (typeCode_)
    {
    case ENGINEER:
        return new Engineer();
    case MANAGER:
        return new Manager();
    default:
        return nullptr;
    }
}
// Employee.cpp
#include "Employee.h"
#include <iostream>

Employee::Employee()
    :monthlySalary(20000), bonus(10000) {}

int Employee::payAmount(int typeCode_)
{
    switch (typeCode_) // Note: typeCode doesn't changed
    {
    case ENGINEER:
        return monthlySalary;
    case MANAGER:
        return monthlySalary + bonus;
    default:
        return 0;
    }
}
// Engineer.cpp
#include "Engineer.h"

int Engineer::getTypeCode()
{
    return Employee::ENGINEER;
}
// Manager.cpp
#include "Manager.h"

int Manager::getTypeCode()
{
    return Employee::MANAGER;
}
// main.cpp
#include "Employee.h"

int main()
{
    Employee* pEmployee = Employee::create(Employee::ENGINEER);
    int pay = pEmployee->payAmount(pEmployee->getTypeCode() );
    delete pEmployee;

    pEmployee = Employee::create(Employee::MANAGER);
    pay = pEmployee->payAmount(pEmployee->getTypeCode() );
    
    delete pEmployee;
    pEmployee = nullptr;
}

2.2 step2-Refactor5

// Employee.h
#pragma once

class Employee
{
private:
    int monthlySalary;
    int bonus; // only Manager has 
public:
    static constexpr int ENGINEER = 0;
    static constexpr int MANAGER = 1;
public:
    Employee();

    static Employee* create(int typeCode_);
    
    // (1) Note1: Conditional func changed to pvf, 
    // no longer need typeCodePara
    // no longer need default branch
    virtual int payAmount() = 0;

    // (2) Note2: original TypeCode attached Class add field getFunc, 
    // used by subClass's vf: payAmount()
    int getMonthlySalary();
    int getBonus();
    
    // (3) Note3: getTypeCode() not need in this demoProgram 
    virtual int getTypeCode() = 0;
};
// Engineer.h
#pragma once
#include "Employee.h"

class Engineer: public Employee
{
public:
    virtual int payAmount();
    
    int getTypeCode();
};
// Manager.h
#pragma once
#include "Employee.h"

class Manager: public Employee
{
public:
    virtual int payAmount();

    int getTypeCode(); 
};
// EmployeeFactor.cpp
#include "Employee.h"
#include "Engineer.h"
#include "Manager.h"

Employee*
Employee::create(int typeCode_)
{
    switch (typeCode_)
    {
    case ENGINEER:
        return new Engineer();
    case MANAGER:
        return new Manager();
    default:
        return nullptr;
    }
}
// Employee.cpp
#include "Employee.h"
#include <iostream>

Employee::Employee()
    :monthlySalary(20000), bonus(10000) {}

int Employee::getMonthlySalary()
{
    return monthlySalary;
}

int Employee::getBonus()
{
    return bonus;
}
// Engineer.cpp
#include "Engineer.h"

int Engineer::payAmount()
{
    return getMonthlySalary();
}

int Engineer::getTypeCode()
{
    return Employee::ENGINEER;
}
// Manager.cpp
#include "Manager.h"

int Manager::payAmount()
{
    return getMonthlySalary() + getBonus();
}

int Manager::getTypeCode()
{
    return Employee::MANAGER;
}
// main.cpp
#include "Employee.h"

int main()
{
    Employee* pEmployee = Employee::create(Employee::ENGINEER);
    // Note: Client vf payAmount() no longer need typeCodePara 
    int pay = pEmployee->payAmount();
    delete pEmployee;

    pEmployee = Employee::create(Employee::MANAGER);
    pay = pEmployee->payAmount();
    
    delete pEmployee;
    pEmployee = nullptr;
}

2.3 step3-Refactor7: Push Down Field & Method 将只与特定子类相关的字段和函数下推到相关子类

只变动4个文件: Employee.h/cpp Manager.h/cpp

// Employee.h
#pragma once

class Employee
{
private:
    // (1) Note1: Push Down Field: Mamager special
    int monthlySalary;
public:
    static constexpr int ENGINEER = 0;
    static constexpr int MANAGER = 1;
public:
    Employee();
    
    static Employee* create(int typeCode_);
    
    virtual int payAmount() = 0;
    int getMonthlySalary();
    // (2) Note2: Push Down Method: Mamager special
    
    virtual int getTypeCode() = 0;
};
// Manager.h
#pragma once
#include "Employee.h"

class Manager: public Employee
{
private:
    int bonus; // only Manager has 
public:
    Manager();

    virtual int payAmount();

    int getBonus(); // only Manager has 
    
    int getTypeCode();
};
// Employee.cpp
#include "Employee.h"
#include <iostream>

Employee::Employee()
    :monthlySalary(20000) {}

int Employee::getMonthlySalary()
{
    return monthlySalary;
}
// Manager.cpp
#include "Manager.h"

Manager::Manager(): bonus(10000) {}

int Manager::payAmount()
{
    return getMonthlySalary() + getBonus();
}

int Manager::getBonus()
{
    return bonus;
}

int Manager::getTypeCode()
{
    return Employee::MANAGER;
}

3 以 State/Strategy 取代 类型码(TypeCode)

3.0 重构前

// Employee.h
#pragma once

class Employee
{
public:
    static constexpr int ENGINEER = 0;
    static constexpr int MANAGER = 1;
private:
    int type;

    int monthlySalary;
    int bonus; 

public:
    Employee(int typeCode_);
    
    int payAmount(); // (1) Note1: Conditional func, getType() to calculate typeCode
    int getType();
    
    void setType(int typeCode_);
};
// Employee.cpp
#include "Employee.h"

Employee::Employee(int typeCode_)
    : type(typeCode_), monthlySalary(20000), bonus(10000){}

int Employee::payAmount()
{
    switch (getType() ) // (2) Note2: typeCode can be change
    {
        case ENGINEER:
            return monthlySalary;
        case MANAGER:
            return monthlySalary + bonus;
        default:
            return 0;
    }   
}
int Employee::getType()
{
    return type;
}

void Employee::setType(int typeCode_)
{
    type = typeCode_;
}
// main.cpp
#include "Employee.h"

int main()
{
    Employee* pEmployee = new Employee(Employee::MANAGER);
    int pay = pEmployee->payAmount();
    pEmployee->setType(Employee::ENGINEER);
    pay = pEmployee->payAmount();
}

3.1 重构 3: 类型码 field 换为 新类的指针 EmployeeType*

// Employee.h
#pragma once
#include "EmployeeType.h" // (1.1) associate / depend

class Employee
{
public:
    static constexpr int ENGINEER = 0;
    static constexpr int MANAGER = 1;
private:
    EmployeeType* type; // (1) Note1: type from int(typeCode) to typeClassPtr
    int monthlySalary;
    int bonus; 
public:
    Employee(int typeCode_); // (2) Note2: Ctor call setType(.)
    void setType(int typeCode_);
    
    int payAmount(); 
    int getType(); // (3) Note3: getType() turn to call type->getTypeCode(); and used in Conditional func payAmount()
    
    ~Employee();
};
// EmployeeType.h 
#pragma once

class EmployeeType
{
public:
    virtual int getTypeCode() = 0;
};
// Engineer.h
#pragma once
#include "EmployeeType.h"

class Engineer: public EmployeeType // (5) Note5: subClass moved to newClass`
{
public:
    int getTypeCode();
};
// Manager.h
#pragma once
#include "EmployeeType.h"

class Manager : public EmployeeType
{
public:
    int getTypeCode();
};
// Employee.cpp
#include "Engineer.h"
#include "Manager.h"

#include "Employee.h"

Employee::Employee(int typeCode_)
    : type(nullptr), monthlySalary(20000), bonus(10000)
{
    setType(typeCode_);
}

void Employee::setType(int typeCode_)
{
    if (type)
    {
        delete type;
        type = nullptr;
    }

    switch (typeCode_) // after refactor, code only has one switch/if, and setType is called when obj ctor or typeCode change
    {
    case ENGINEER:  
        type = new Engineer();
        break;
    case MANAGER:
        type = new Manager();
        break;
    default:
        type = nullptr;
    }
}

int Employee::payAmount()
{
    switch (getType() ) // (4) Note4: typeCode can be change
    {
        case ENGINEER:
            return monthlySalary;
        case MANAGER:
            return monthlySalary + bonus;
        default:
            return 0;
    }   
}

int Employee::getType()
{
    return type->getTypeCode();
}

Employee::~Employee()
{
    if (type)
        delete type;
}
// Engineer.cpp
#include "Employee.h"
#include "Engineer.h"

int Engineer::getTypeCode()
{
    return Employee::ENGINEER;
}
// Manager.cpp
#include "Employee.h"
#include "Manager.h"

int Manager::getTypeCode()
{
    return Employee::MANAGER;
}
// main.cpp
#include "Employee.h"

int main()
{
    Employee* pEmployee = new Employee(Employee::MANAGER);
    int pay = pEmployee->payAmount();

    pEmployee->setType(Employee::ENGINEER);
    pay = pEmployee->payAmount();

    delete pEmployee;
}

3.2 重构 6: 将 类型码 info(类型码枚举值/编译期常量 ENGINEER / MANAGER)子类(Engineer / Manager) info 均移到 新类 EmployeeType

// Employee.h
#pragma once
#include "EmployeeType.h" 

class Employee
{
private:
    EmployeeType* type; 
    int monthlySalary;
    int bonus; 
public:
    // (1) Note1: Ctor(int typeCode_) -> setType(int typeCode_) -> newType(int typeCode)
    Employee(int typeCode_);
    void setType(int typeCode_);
    
    int payAmount();
    int getType();
    
    ~Employee();
};
// EmployeeType.h
#pragma once

class EmployeeType
{
public:
    // (3) Note3: typeCode enumValue moved to newClass
    static constexpr int ENGINEER = 0;
    static constexpr int MANAGER = 1;
public:
    // (2) Note2: Factory Method, provide subClassObj,
    //   `subClass info( return new Engineer() )` all moved to EmployeeType
    static EmployeeType* newType(int typeCode);
    
    virtual int getTypeCode() = 0;
};
// Engineer.h
#pragma once
#include "EmployeeType.h"

class Engineer: public EmployeeType
{
public:
    int getTypeCode();
};
// Manager.h
#pragma once
#include "EmployeeType.h"

class Manager: public EmployeeType
{
public:
    int getTypeCode();
};
// EmployeeTypeFactory.cpp
#include "EmployeeType.h"
#include "Engineer.h"
#include "Manager.h"

EmployeeType* 
EmployeeType::newType(int typeCode_)
{
    switch (typeCode_) // after refactor, code only has one switch/if, and setType is called when obj ctor or typeCode change
    {
    case ENGINEER:
        return new Engineer();
    case MANAGER:
        return new Manager();
    default:
        return nullptr;
    }
}
// Employee.cpp
#include "Employee.h"

Employee::Employee(int typeCode_)
    : type(nullptr), monthlySalary(20000), bonus(10000)
{
    setType(typeCode_);
}

void Employee::setType(int typeCode_)
{
    if (type)
    {
        delete type;
        type = nullptr;
    }
    
    // Note: 
    type = EmployeeType::newType(typeCode_);
}

int Employee::payAmount()
{
    switch (getType() )
    {
    case EmployeeType::ENGINEER:
        return monthlySalary;
    case EmployeeType::MANAGER:
        return monthlySalary + bonus;
    default:
        return 0;
    }   
}

int Employee::getType()
{
    return type->getTypeCode();
}

Employee::~Employee()
{
    if (type)
        delete type;
}
// Engineer.cpp
#include "Engineer.h"

int Engineer::getTypeCode()
{
    return EmployeeType::ENGINEER;
}
// Manager.cpp
#include "Manager.h"

int Manager::getTypeCode()
{
    return EmployeeType::MANAGER;
}
// main.cpp
#include "Employee.h"

int main()
{
    Employee* pEmployee = new Employee(EmployeeType::MANAGER);
    int pay = pEmployee->payAmount();

    pEmployee->setType(EmployeeType::ENGINEER);
    pay = pEmployee->payAmount();

    delete pEmployee;
}

3.3 重构5

处理 条件函数 payAmount(): 含条件语句(switch/if)

payAmount() 从 原宿主类(Employee) 移到 新类层次(EmployeeType)

[1] payAmount() 所属对象指针 this 作实参转调 新类层次新增的 vf: payAmount(Employee* )

[2] 条件分支的 每个分支 -> 对应的 具体子类(Engineer/Manager)

// Employee.h
#pragma once
#include "EmployeeType.h" 

class Employee
{
private:
    EmployeeType* type; 
    int monthlySalary;
    int bonus;
public:
    Employee(int typeCode_);
    void setType(int typeCode_);
    
    // (1) Note1: Conditional Func changed to call newClass's Additional vf type->payAmount(this)
    int payAmount();
    int getMonthlySalary();
    int getBonus();
    
    ~Employee();
    
    int getType(); // (5) Note5: getType() not used 
};
// EmployeeType.h
#pragma once
class Employee; // (3) Note3: newClass's headerFile should forward declare original attached Class rather than include its headerFile, 
                //              otherwise, include circularly
class EmployeeType
{
public:
    static constexpr int ENGINEER = 0;
    static constexpr int MANAGER = 1;
public:
    static EmployeeType* newType(int typeCode);

    // (2) Note2: Add vf to newClass, with para = attached Class ptr: Replace Conditional with Polymorphism
    virtual int payAmount(Employee* pEmployee) = 0;
    
    virtual int getTypeCode() = 0; // (6) Note6: getType() not used 
};
// Engineer.h
#pragma once

// (4) Note4: 具体子类(Engineer.h) include(依赖)新类(EmployeeType.h) 和原宿主类(Employee.h), 
// 但新类不 include(而是 前向声明)原宿主类 => include(依赖) 不构成环
#include "EmployeeType.h" 
#include "Employee.h"   

class Engineer: public EmployeeType
{
public:
    virtual int payAmount(Employee* pEmployee);
    
    int getTypeCode();
};
// Manager.h
#pragma once
#include "EmployeeType.h"
#include "Employee.h"

class Manager: public EmployeeType
{
public:
    virtual int payAmount(Employee* pEmployee);
    
    int getTypeCode();
};
// EmployeeTypeFactory.cpp
#include "EmployeeType.h"
#include "Engineer.h"
#include "Manager.h"

EmployeeType* 
EmployeeType::newType(int typeCode_)
{
    switch (typeCode_) 
    {
    case ENGINEER:
        return new Engineer();
    case MANAGER:
        return new Manager();
    default:
        return nullptr;
    }
}
// Employee.cpp
#include "Employee.h"

Employee::Employee(int typeCode_)
    : type(nullptr), monthlySalary(20000), bonus(10000)
{
    setType(typeCode_);
}

void Employee::setType(int typeCode_)
{
    if (type)
    {
        delete type;
        type = nullptr;
    }
    type = EmployeeType::newType(typeCode_);
}

int Employee::payAmount()
{
    return type->payAmount(this);
}

int Employee::getMonthlySalary()
{
    return monthlySalary;
}

int Employee::getBonus()
{
    return bonus;
}

int Employee::getType()
{
    return type->getTypeCode();
}
Employee::~Employee()
{
    if (type)
        delete type;
}
// Engineer.cpp
#include "Engineer.h"
 
int Engineer::payAmount(Employee* pEmployee)
{
    return pEmployee->getMonthlySalary();
}

int Engineer::getTypeCode()
{
    return EmployeeType::ENGINEER;
}
// Manager.cpp
#include "Manager.h"

int Manager::payAmount(Employee* pEmployee)
{
    return pEmployee->getMonthlySalary() + pEmployee->getBonus();
}

int Manager::getTypeCode()
{
    return EmployeeType::MANAGER;
}
// main.cpp
#include "Employee.h"

int main()
{
    Employee* pEmployee = new Employee(EmployeeType::MANAGER);
    int pay = pEmployee->payAmount();

    pEmployee->setType(EmployeeType::ENGINEER);
    pay = pEmployee->payAmount();

    delete pEmployee;
}

3.4 重构 7: Push Down Field & Method

方法同 2.3

相关文章