行为型模式-模板方法模式

发布时间 2023-11-21 14:07:17作者: Qt小罗

1 什么是模板方法模式

模板方法模式是一种行为设计模式,它定义了一个算法的骨架,将一些步骤的具体实现延迟到子类中。这样可以在不改变算法结构的情况下,允许子类根据自身的需求来实现特定的步骤。

模板方法模式通常由一个抽象基类提供一个模板方法,该方法定义了算法的骨架,并调用一系列的抽象和/或具体方法。子类继承该抽象基类并实现其中的具体方法,从而实现自己的算法步骤,但不能改变算法的整体结构。

模板方法模式的关键要素包括:

  • 抽象基类(Abstract Base Class):提供了算法的骨架,定义了模板方法和抽象方法,用于规定算法各个步骤的执行顺序。
  • 具体子类(Concrete Subclass):继承抽象基类,实现具体的算法细节,即实现抽象方法,以定制算法的特定步骤。
  • 模板方法(Template Method):位于抽象基类中的方法,定义了算法的骨架,包含一系列的步骤调用,可以是具体方法或抽象方法。
  • 钩子方法(Hook Method):位于抽象基类中的可选方法,可供子类选择实现,用于在模板方法中定制算法行为。
  • 具体方法(Concrete Method):位于抽象基类中的方法,提供算法中共同的实现逻辑,被模板方法和子类共享调用。

2 举个例子

下面以制作咖啡和茶为例来说明模板方法模式:

#include <iostream>

// 抽象基类:饮料
class Beverage {
public:
    // 模板方法,定义了算法的骨架
    void prepareBeverage() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
        // 钩子方法,子类可以选择性地覆盖它
        if (customerWantsCondiments()) {
            addExtraCondiments();
        }
    }

    // 具体方法:烧水
    void boilWater() {
        std::cout << "烧水" << std::endl;
    }

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

    // 具体方法:倒入杯中
    void pourInCup() {
        std::cout << "倒入杯中" << std::endl;
    }

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

    // 钩子方法:加入额外调料,子类可以选择实现它
    virtual void addExtraCondiments() {}

    // 钩子方法:询问客户是否需要额外调料,默认返回 true
    virtual bool customerWantsCondiments() {
        return true;
    }
};

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

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

    virtual bool customerWantsCondiments() override {
        // 这里我们覆盖了钩子方法,并返回 false 表示客户不需要额外调料
        return false;
    }
};

// 具体类:茶
class Tea : public Beverage {
public:
    virtual void brew() override {
        std::cout << "冲泡茶叶" << std::endl;
    }

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

    virtual void addExtraCondiments() override {
        std::cout << "加入蜂蜜" << std::endl;
    }
};

// 客户端代码
int main() {
    Beverage* coffee = new Coffee();
    coffee->prepareBeverage();

    std::cout << "\n";

    Beverage* tea = new Tea();
    tea->prepareBeverage();

    delete coffee;
    delete tea;

    return 0;
}

在这个示例中,抽象基类 Beverage 定义了算法的骨架,其中 prepareBeverage 方法是一个模板方法,定义了一系列烧水、冲泡、倒入杯中、添加调料等步骤。具体的步骤被定义为虚方法,需要由子类来实现。

Coffee 和 Tea 类分别是子类,它们继承了 Beverage 类并实现了其中的抽象方法。每个子类可以根据自己的需求来具体实现 brew 和 addCondiments 方法,以定制自己的饮料制作过程。同时,它们也可以覆盖 customerWantsCondiments 和 addExtraCondiments 方法,根据需要对饮料进行个性化的调整。

在客户端代码中,我们创建了 Coffee 和 Tea 对象,并调用它们的 prepareBeverage 方法。由于 prepareBeverage 是模板方法,因此它们的制作过程都按照算法骨架执行,但是具体的实现细节可以根据每个子类的需求进行定制。

这样,我们就使用模板方法模式实现了制作咖啡和茶的例子。模板方法模式允许我们定义算法的骨架,同时又保留了对具体步骤实现的灵活性。

3 总结

模板方法模式提供了一种在不改变算法结构的情况下,允许子类自定义部分算法步骤的灵活性。它是一种常用的设计模式,可以应用于各种场景,例如算法、框架以及生命周期管理等。