模板方法模式(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;
}