模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个操作中的算法骨架,而将一些步骤延迟到子类中实现。这种模式使得子类可以在不改变算法结构的情况下,重新定义算法中的某些特定步骤。

模板方法模式的核心角色

  1. 抽象类(Abstract Class):定义算法的骨架(模板方法),并声明一些抽象的primitive方法供子类实现
  2. 具体子类(Concrete Class):实现抽象类中声明的primitive方法,完成算法中与具体子类相关的步骤

模板方法模式的实现示例

下面以"饮料制作流程"为例展示模板方法模式的实现,冲泡咖啡和泡茶的流程相似但某些步骤不同,我们可以用模板方法定义通用流程:

#include <iostream>
#include <string>

// 抽象类:饮料
class Beverage {
public:
    // 模板方法:定义算法骨架,声明为final防止子类重写
    void prepareRecipe() final {
        boilWater();      // 煮沸水
        brew();           // 冲泡(子类实现)
        pourInCup();      // 倒入杯子
        if (customerWantsCondiments()) {  // 钩子方法:是否加调料
            addCondiments();  // 添加调料(子类实现)
        }
    }

    // 抽象方法:冲泡
    virtual void brew() = 0;

    // 抽象方法:添加调料
    virtual void addCondiments() = 0;

    // 具体方法:煮沸水(所有饮料通用)
    void boilWater() {
        std::cout << "煮沸水" << std::endl;
    }

    // 具体方法:倒入杯子(所有饮料通用)
    void pourInCup() {
        std::cout << "倒入杯子中" << std::endl;
    }

    // 钩子方法:默认返回true,表示加调料
    virtual bool customerWantsCondiments() {
        return true;
    }

    virtual ~Beverage() = default;
};

// 具体子类:咖啡
class Coffee : public Beverage {
public:
    void brew() override {
        std::cout << "用沸水冲泡咖啡粉" << std::endl;
    }

    void addCondiments() override {
        std::cout << "添加糖和牛奶" << std::endl;
    }

    // 重写钩子方法:询问用户是否需要调料
    bool customerWantsCondiments() override {
        std::string answer;
        std::cout << "请问需要为您的咖啡添加糖和牛奶吗?(y/n) ";
        std::cin >> answer;
        return answer == "y" || answer == "Y";
    }
};

// 具体子类:茶
class Tea : public Beverage {
public:
    void brew() override {
        std::cout << "用沸水浸泡茶叶" << std::endl;
    }

    void addCondiments() override {
        std::cout << "添加柠檬" << std::endl;
    }

    // 可以选择不重写钩子方法,使用父类默认实现
};

// 客户端使用
int main() {
    std::cout << "=== 制作咖啡 ===" << std::endl;
    Beverage* coffee = new Coffee();
    coffee->prepareRecipe();

    std::cout << "\n=== 制作茶 ===" << std::endl;
    Beverage* tea = new Tea();
    tea->prepareRecipe();

    // 清理资源
    delete coffee;
    delete tea;

    return 0;
}
   

模板方法模式的核心概念

  • 模板方法(Template Method):定义算法的骨架,通常声明为final防止子类重写
  • Primitive方法:抽象方法,由子类实现,是算法中的可变步骤
  • 具体方法(Concrete Method):在抽象类中实现,是算法中的固定步骤
  • 钩子方法(Hook Method):在抽象类中提供默认实现(通常为空),子类可以选择性重写,用于控制算法流程

模板方法模式的工作原理

  1. 抽象类定义算法的整体框架(模板方法)
  2. 模板方法按顺序调用一系列方法,包括具体方法、抽象方法和钩子方法
  3. 具体方法在抽象类中实现,提供所有子类都需要的共同功能
  4. 抽象方法由子类实现,提供特定于子类的功能
  5. 钩子方法可以被子类重写,用于改变算法的流程或行为

模板方法模式与策略模式的区别

  • 模板方法模式:通过继承实现算法的变化,算法骨架固定,步骤实现可变
  • 策略模式:通过组合实现算法的变化,整个算法可以被替换

模板方法模式的应用场景

  1. 多个子类有公共的方法,且逻辑基本相同时
  2. 需要固定算法骨架,只允许改变其中某些步骤时
  3. 需要控制子类扩展的场景(钩子方法可以限制扩展)
  4. 框架设计中,用于定义扩展点(如框架中的生命周期方法)

模板方法模式的优缺点

优点

  • 封装了不变部分,扩展了可变部分,符合开放-封闭原则
  • 提取了公共代码,减少了代码冗余
  • 子类只需要实现自己关心的步骤,简化了子类的实现
  • 控制了算法的整体结构,确保了算法的一致性

缺点

  • 模板方法引入了反向控制结构,子类执行的结果影响父类,增加了代码理解难度
  • 如果算法骨架需要修改,必须修改抽象类,可能影响所有子类
  • 可能导致类数量增加,每个不同的实现都需要一个子类

模板方法模式在C++的许多框架中都有广泛应用,例如MFC中的CWnd类体系,定义了窗口的生命周期模板方法;STL中的迭代器模式也间接使用了模板方法的思想。在框架设计中,模板方法模式是一种常用的设计手段,用于定义框架的骨架和扩展点。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐