(10)模板模式

模板方法模式(Template Method Pattern) 是一种 行为型设计模式
核心思想:
 - 在父类中定义一个算法的骨架(模板),而将一些步骤的实现延迟到子类中。
 - 父类控制算法结构,子类可以重新定义某些步骤,但不能改变算法的整体流程。

特点:
 - 算法骨架固定,由父类的 templateMethod() 定义
 - 步骤可变,某些步骤由,virtual 函数定义,子类可重写
 - 防止子类修改流程,templateMethod() 通常是 final
 - 代码复用高, 公共逻辑在父类实现
业务场景:企业员工工资单生成系统
不同类型的员工(全职、兼职、外包)的工资单计算流程结构相同,但细节不同:
 - 工资单生成流程(算法骨架)
 - 打印抬头(所有员工相同)
 - 计算基本工资(不同)
 - 计算奖金(不同)
 - 计算扣款(不同)
 - 打印总计(通用)
 - 生成 PDF 报告(通用)
 - 我们使用 模板方法模式 来统一流程,允许子类自定义计算步骤。
#include <iostream>
#include <string>
#include <memory>
#include <iomanip>

using std::string;
using std::unique_ptr;

// ==================== 员工工资单抽象类(模板类)====================
class PayrollTemplate {
protected:
    string employeeName;
    int workDays;

    // 抽象方法:由子类实现
    virtual double calculateBaseSalary() const = 0;
    virtual double calculateBonus() const = 0;
    virtual double calculateDeductions() const = 0;

    // 钩子方法(Hook):子类可选重写
    virtual void onBeforePrint() const {
        // 默认为空,子类可扩展
    }

    virtual void onAfterPrint() const {
        std::cout << "已发送工资单邮件通知\n";
    }

public:
    PayrollTemplate(const string& name, int days) 
        : employeeName(name), workDays(days) {}

    virtual ~PayrollTemplate() = default;

    // 模板方法:定义算法骨架(不允许子类重写)
    void generatePayroll() const final {
        std::cout << std::fixed << std::setprecision(2);
        std::cout << "\n" << std::string(40, '=') << "\n";
        std::cout << "          工资单\n";
        std::cout << std::string(40, '=') << "\n";
        std::cout << "员工: " << employeeName << "\n";
        std::cout << "工作天数: " << workDays << " 天\n";

        onBeforePrint(); // 钩子

        double base = calculateBaseSalary();
        double bonus = calculateBonus();
        double deductions = calculateDeductions();

        double total = base + bonus - deductions;

        std::cout << "基本工资: " << base << " 元\n";
        std::cout << "奖金:     " << bonus << " 元\n";
        std::cout << "扣款:     " << deductions << " 元\n";
        std::cout << "---------\n";
        std::cout << "实发:     " << total << " 元\n";

        onAfterPrint(); // 钩子
        std::cout << "\n";
    }
};
//=================全职员工工资单======================
class FullTimePayroll : public PayrollTemplate {
private:
    double monthlySalary;

public:
    FullTimePayroll(const string& name, double salary)
        : PayrollTemplate(name, 22), monthlySalary(salary) {}

    double calculateBaseSalary() const override {
        return monthlySalary * (static_cast<double>(workDays) / 22);
    }

    double calculateBonus() const override {
        return monthlySalary * 0.1; // 10% 年终奖
    }

    double calculateDeductions() const override {
        return monthlySalary * 0.2; // 社保公积金等
    }

    void onAfterPrint() const override {
        std::cout << "全职员工额外福利:年度体检\n";
        PayrollTemplate::onAfterPrint();
    }
};
//====================兼职员工工资单======================
class PartTimePayroll : public PayrollTemplate {
private:
    double hourlyRate;

public:
    PartTimePayroll(const string& name, double rate, int days)
        : PayrollTemplate(name, days), hourlyRate(rate) {}

    double calculateBaseSalary() const override {
        return hourlyRate * 8 * workDays; // 每天8小时
    }

    double calculateBonus() const override {
        return workDays > 15 ? 200.0 : 0.0; // 满15天奖励200
    }

    double calculateDeductions() const override {
        return 0.0; // 兼职无扣款
    }

    void onBeforePrint() const override {
        std::cout << "注意:此为兼职员工工资单,不享受正式福利\n";
    }
};
//====================外包员工工资单======================
class ContractorPayroll : public PayrollTemplate {
private:
    double dailyRate;

public:
    ContractorPayroll(const string& name, double rate, int days)
        : PayrollTemplate(name, days), dailyRate(rate) {}

    double calculateBaseSalary() const override {
        return dailyRate * workDays;
    }

    double calculateBonus() const override {
        return 0.0; // 外包无奖金
    }

    double calculateDeductions() const override {
        return dailyRate * workDays * 0.05; // 手续费 5%
    }

    void onAfterPrint() const override {
        std::cout << "外包合同编号: CT2025-" << employeeName << "\n";
        PayrollTemplate::onAfterPrint();
    }
};
int main() {
    std::cout << "欢迎使用企业工资单系统\n\n";

    // 创建不同类型的工资单
    unique_ptr<PayrollTemplate> payroll1 = 
        std::make_unique<FullTimePayroll>("张三", 15000.0);

    unique_ptr<PayrollTemplate> payroll2 = 
        std::make_unique<PartTimePayroll>("李四", 50.0, 20);

    unique_ptr<PayrollTemplate> payroll3 = 
        std::make_unique<ContractorPayroll>("王五", 800.0, 15);

    // 生成工资单(调用模板方法)
    payroll1->generatePayroll();
    payroll2->generatePayroll();
    payroll3->generatePayroll();

    return 0;
}
模板方法模式进行优化,将原本基于继承 + 虚函数的实现,升级为 基于模板的静态多态(Static Polymorphism) 实现。
使用CRTP(Curiously Recurring Template Pattern)模式:
 - 零成本抽象
 - 编译期绑定,性能更高
 - 无虚函数开销
 - 支持内联优化
#include <iostream>
#include <string>
#include <iomanip>

// ==================== 通用工资单模板类(CRTP)====================
template<typename Impl>
class PayrollTemplate {
protected:
    std::string employeeName;
    int workDays;

public:
    PayrollTemplate(const std::string& name, int days)
        : employeeName(name), workDays(days) {}

    // 模板方法:生成工资单(final,不可重写)
    void generatePayroll() const {
        printHeader();

        // 使用静态多态调用子类实现
        const Impl& impl = static_cast<const Impl&>(*this);
        double base = impl.calculateBaseSalary();
        double bonus = impl.calculateBonus();
        double deductions = impl.calculateDeductions();

        // 钩子:前置操作
        impl.onBeforePrint();

        printDetails(base, bonus, deductions);

        // 钩子:后置操作
        impl.onAfterPrint();
        std::cout << "\n";
    }

private:
    void printHeader() const {
        std::cout << std::string(40, '=') << "\n";
        std::cout << "          工资单\n";
        std::cout << std::string(40, '=') << "\n";
        std::cout << "员工: " << employeeName << "\n";
        std::cout << "工作天数: " << workDays << " 天\n";
    }

    void printDetails(double base, double bonus, double deductions) const {
        std::cout << std::fixed << std::setprecision(2);
        std::cout << "基本工资: " << base << " 元\n";
        std::cout << "奖金:     " << bonus << " 元\n";
        std::cout << "扣款:     " << deductions << " 元\n";
        std::cout << "---------\n";
        std::cout << "实发:     " << (base + bonus - deductions) << " 元\n";
    }
};
使用模板继承
class FullTimePayroll : public PayrollTemplate<FullTimePayroll> {
    double monthlySalary;

public:
    FullTimePayroll(const std::string& name, double salary)
        : PayrollTemplate(name, 22), monthlySalary(salary) {}

    // 所有方法必须是 const,以匹配模板中的 const 调用
    double calculateBaseSalary() const {
        return monthlySalary * (static_cast<double>(workDays) / 22);
    }

    double calculateBonus() const {
        return monthlySalary * 0.1; // 10% 奖金
    }

    double calculateDeductions() const {
        return monthlySalary * 0.2; // 20% 扣款
    }

    void onBeforePrint() const {
        // 空
    }

    void onAfterPrint() const {
        std::cout << "全职员工额外福利:年度体检\n";
        std::cout << "已发送工资单邮件通知\n";
    }
};
class PartTimePayroll : public PayrollTemplate<PartTimePayroll> {
    double hourlyRate;

public:
    PartTimePayroll(const std::string& name, double rate, int days)
        : PayrollTemplate(name, days), hourlyRate(rate) {}

    double calculateBaseSalary() const {
        return hourlyRate * 8 * workDays;
    }

    double calculateBonus() const {
        return workDays > 15 ? 200.0 : 0.0;
    }

    double calculateDeductions() const {
        return 0.0;
    }

    void onBeforePrint() const {
        std::cout << "注意:此为兼职员工工资单,不享受正式福利\n";
    }

    void onAfterPrint() const {
        std::cout << "已发送工资单邮件通知\n";
    }
};
class ContractorPayroll : public PayrollTemplate<ContractorPayroll> {
    double dailyRate;

public:
    ContractorPayroll(const std::string& name, double rate, int days)
        : PayrollTemplate(name, days), dailyRate(rate) {}

    double calculateBaseSalary() const {
        return dailyRate * workDays;
    }

    double calculateBonus() const {
        return 0.0;
    }

    double calculateDeductions() const {
        return dailyRate * workDays * 0.05; // 5% 手续费
    }

    void onBeforePrint() const {
        // 空
    }

    void onAfterPrint() const {
        std::cout << "外包合同编号: CT2025-" << employeeName << "\n";
        std::cout << "已发送工资单邮件通知\n";
    }
};
int main() {
    std::cout << "欢迎使用高性能工资单系统(CRTP 版)\n\n";

    FullTimePayroll  fullTime("张三", 15000.0);
    PartTimePayroll  partTime("李四", 50.0, 20);
    ContractorPayroll contractor("王五", 800.0, 15);

    fullTime.generatePayroll();
    partTime.generatePayroll();
    contractor.generatePayroll();

    return 0;
}
posted @ 2018-12-13 21:28  osbreak  阅读(141)  评论(0)    收藏  举报