当前位置: 首页 > article >正文

C++实现设计模式---模板方法模式 (Template Method)

模板方法模式 (Template Method)

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


意图

  • 在一个方法中定义算法的骨架,而将某些具体步骤延迟到子类中实现。
  • 让子类可以在不改变算法整体结构的情况下重新定义算法的某些步骤。

使用场景

  1. 多个类有相同的操作步骤,但具体实现不同
    • 当多个类的操作有一致的结构,但实现不同,可以使用模板方法模式。
  2. 希望控制算法的结构
    • 父类定义算法骨架,子类实现具体步骤。
  3. 避免代码重复
    • 将公共逻辑抽取到父类中,具体逻辑在子类中实现。

参与者角色

  1. 抽象类 (AbstractClass)
    • 定义算法的骨架,并包含一个或多个抽象方法,子类需要实现这些方法。
    • 提供一个模板方法,定义算法的整体结构。
  2. 具体类 (ConcreteClass)
    • 实现抽象类中的抽象方法,提供算法的具体步骤。

示例代码

以下代码展示了模板方法模式的实现,用于模拟制作饮品的过程。不同的饮品(如茶和咖啡)有相同的制作步骤,但某些步骤的实现不同。

#include <iostream>

// 抽象类:饮品
class Beverage {
public:
    virtual ~Beverage() = default;

    // 模板方法:定义饮品制作的算法骨架
    void prepareRecipe() {
        boilWater();           // 1. 煮沸水
        brew();                // 2. 冲泡
        pourInCup();           // 3. 倒入杯中
        if (customerWantsCondiments()) { // 4. 是否添加调料
            addCondiments();   // 添加调料
        }
    }

protected:
    // 基本操作
    void boilWater() {
        std::cout << "将水煮沸。
";
    }

    void pourInCup() {
        std::cout << "将饮品倒入杯中。
";
    }

    // 抽象操作:由子类实现
    virtual void brew() = 0;
    virtual void addCondiments() = 0;

    // Hook(钩子方法):子类可选择重写
    virtual bool customerWantsCondiments() {
        return true; // 默认需要添加调料
    }
};

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

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

// 具体类:咖啡
class Coffee : public Beverage {
protected:
    void brew() override {
        std::cout << "用热水冲泡咖啡。
";
    }

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

    // 重写钩子方法
    bool customerWantsCondiments() override {
        char answer;
        std::cout << "是否需要添加牛奶和糖?(y/n): ";
        std::cin >> answer;
        return (answer == 'y' || answer == 'Y');
    }
};

// 客户端代码
int main() {
    std::cout << "制作茶:
";
    Tea tea;
    tea.prepareRecipe();

    std::cout << "
制作咖啡:
";
    Coffee coffee;
    coffee.prepareRecipe();

    return 0;
}

代码解析

1. 抽象类 (Beverage)
  • 定义了模板方法 prepareRecipe,它包含制作饮品的算法骨架。
  • 提供了基本操作(如 boilWaterpourInCup),以及抽象操作(如 brewaddCondiments),具体实现由子类完成。
  • 包含钩子方法 customerWantsCondiments,允许子类自定义是否执行某些步骤。
class Beverage {
public:
    virtual ~Beverage() = default;

    void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        if (customerWantsCondiments()) {
            addCondiments();
        }
    }

protected:
    void boilWater() { std::cout << "将水煮沸。
"; }
    void pourInCup() { std::cout << "将饮品倒入杯中。
"; }

    virtual void brew() = 0;
    virtual void addCondiments() = 0;

    virtual bool customerWantsCondiments() { return true; }
};
2. 具体类 (Tea, Coffee)
  • Tea
    • 实现了 brewaddCondiments 方法,定义了茶的制作方式。
  • Coffee
    • 实现了 brewaddCondiments 方法,定义了咖啡的制作方式。
    • 重写了 customerWantsCondiments 方法,允许用户选择是否添加调料。
class Tea : public Beverage {
protected:
    void brew() override { std::cout << "用热水浸泡茶叶。
"; }
    void addCondiments() override { std::cout << "添加柠檬。
"; }
};
3. 客户端代码
  • 客户端通过调用模板方法 prepareRecipe 来制作饮品,具体实现由子类决定。
int main() {
    Tea tea;
    tea.prepareRecipe();

    Coffee coffee;
    coffee.prepareRecipe();
}

优缺点

优点
  1. 复用代码
    • 将公共逻辑抽取到模板方法中,减少代码重复。
  2. 灵活性
    • 子类可以通过实现抽象方法或重写钩子方法来自定义算法的某些步骤。
  3. 控制算法结构
    • 父类定义算法结构,保证子类不会破坏算法整体逻辑。
缺点
  1. 对子类的依赖
    • 子类需要实现抽象方法,可能导致类的数量增加。
  2. 模板方法难以扩展
    • 如果模板方法需要修改,可能会影响所有子类。

适用场景

  1. 多个子类有相同的算法结构,但实现不同
    • 如制作不同饮品的过程。
  2. 希望控制算法的执行流程
    • 父类定义算法骨架,子类实现具体步骤。
  3. 需要扩展算法的某些步骤
    • 通过子类实现具体步骤,保证算法结构不变。

总结

模板方法模式通过定义算法的骨架,将具体实现延迟到子类中,从而实现代码复用和灵活扩展。它特别适用于算法结构固定但某些步骤实现不同的场景。


http://www.kler.cn/a/501376.html

相关文章:

  • mac intel芯片下载安卓模拟器
  • 整数和浮点数的存储
  • Oracle重启后业务连接大量library cache lock
  • MDX语言的函数实现
  • 超简单,使用Kube-Vip实现K8s高可用VIP详细教程
  • macOS 安装tomcat9
  • Git的master 分支和main分支的区别是什么?使用场景是什么?底层原理是什么?
  • nginx负载均衡-基于端口的负载均衡(一)
  • 提升 PHP 编码效率的 10 个实用函数
  • 基于改进粒子群优化的无人机最优能耗路径规划
  • 大数据环境搭建进度
  • C# 正则表达式完全指南
  • 2025年华数杯国际赛B题论文首发+代码开源 数据分享+代码运行教学
  • 无人机电池技术引领低空经济新篇章!
  • 【网络云SRE运维开发】2025第2周-每日【2025/01/12】小测-【第12章 rip路由协议】理论和实操考试题
  • 【黑灰产】假钱包推广套路
  • SpringBoot项目实战(41)--Beetl网页使用自定义函数获取新闻列表
  • Linux随记(十四)
  • R语言的正则表达式
  • ssh+frp+公网IP 实现远程访问家里的电脑
  • 力扣-数组-219 存在重复元素Ⅱ
  • OceanBase环境搭建与熟悉全攻略:开启分布式数据库探索之旅
  • 生态水文研究中的机器学习与数学建模方法选择
  • 代码随想录算法训练营第二十八天-贪心算法-55. 跳跃游戏
  • 青少年编程与数学 02-006 前端开发框架VUE 21课题、路由控制
  • 【杂谈】-50+个生成式人工智能面试问题(二)