周口市网站建设_网站建设公司_内容更新_seo优化
2025/12/20 20:48:12 网站建设 项目流程

1.模板方法

代码示例

#include <iostream>
using namespace std;// 1. 抽象基类:定义算法骨架
class ZooShow {
public:// 构造函数初始化 expired 状态ZooShow(bool isExpired = false) : expired(isExpired) {}virtual ~ZooShow() {}// 【模板方法】定义骨架// 逻辑完全照搬图片:先看Show0结果,决定是否PlayGame,然后按序执行void Show() {if (Show0()) {PlayGame();}Show1();Show2();Show3();}private:bool expired; // 模拟图片中的私有变量// 私有方法:子类不可见,不可修改,只能由父类流程调用void PlayGame() {cout << "  >> [中场福利] 既然没有超时,那就来玩个游戏吧!(after Show0, then play game)" << endl;}protected:// 【钩子方法】(Hook)// 图片中的逻辑:打印 show0,并判断是否过期virtual bool Show0() {cout << "  [系统检查] 正在检查流程是否超时(Show0)..." << endl;if (!expired) {return true; // 没过期,返回 true,允许玩游戏}return false; // 过期了,返回 false,跳过游戏}// 【原语操作】具体的表演细节,留给子类实现virtual void Show1() = 0;virtual void Show2() = 0;virtual void Show3() = 0;
};// -----------------------------------------------------------// 2. 具体子类 A:海豚表演 (状态:未超时)
class DolphinShow : public ZooShow {
public:DolphinShow() : ZooShow(false) {} // 传入 false,代表没超时protected:// 海豚表演直接使用父类的 Show0 逻辑,不需要重写钩子void Show1() override { cout << "  (海豚) 表演项目一:水上芭蕾" << endl; }void Show2() override { cout << "  (海豚) 表演项目二:算术计算" << endl; }void Show3() override { cout << "  (海豚) 表演项目三:高空顶球" << endl; }
};// 3. 具体子类 B:狮子表演 (状态:已超时)
class LionShow : public ZooShow {
public:LionShow() : ZooShow(true) {} // 传入 true,代表超时了protected:// 狮子表演也使用父类的 Show0 逻辑// 因为 expired 为 true,父类 Show0 会返回 false,从而跳过 PlayGamevoid Show1() override { cout << "  (狮子) 表演项目一:钻火圈" << endl; }void Show2() override { cout << "  (狮子) 表演项目二:吼叫" << endl; }void Show3() override { cout << "  (狮子) 表演项目三:过独木桥" << endl; }
};// 4. 具体子类 C:特殊表演 (强行重写钩子)
class MagicShow : public ZooShow {
protected:// 魔术表演很特殊,不管是否超时,我都强制想玩游戏// 这里演示了子类“挂钩”并修改父类默认判断逻辑的能力bool Show0() override {cout << "  [魔术特权] 无视时间限制,强制开启游戏!" << endl;return true; }void Show1() override { cout << "  (魔术) 大变活人" << endl; }void Show2() override { cout << "  (魔术) 逃脱术" << endl; }void Show3() override { cout << "  (魔术) 消失" << endl; }
};// -----------------------------------------------------------int main() {cout << "=== 第一场:海豚表演 (正常时间) ===" << endl;ZooShow* show1 = new DolphinShow();show1->Show();delete show1;cout << endl;cout << "=== 第二场:狮子表演 (已超时) ===" << endl;ZooShow* show2 = new LionShow();show2->Show(); // 注意观察:这里不会打印 "PlayGame" 的内容delete show2;cout << endl;cout << "=== 第三场:魔术表演 (重写钩子) ===" << endl;ZooShow* show3 = new MagicShow();show3->Show();delete show3;return 0;
}

1. 定义

  • 原文: 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。
  • 解读:
    • “算法的骨架”:指的是我们在父类 ZooShow 中写的 Show() 函数。它规定了“先判断Show0,再PlayGame,再Show1...”这个死流程。
    • “延迟到子类”:指的是具体的 Show1(), Show2() 怎么做,父类不管,留给子类(海豚、鹦鹉)去写。
  • 核心价值: 子类可以在不改变算法结构(不修改 Show() 函数里的流程)的情况下,重定义算法的某些特定步骤

2. 解决的问题 (Stable vs. Changing)

这是设计模式的精髓——分离变与不变。

  • 稳定点 (Stable):算法骨架
    • ZooShow 的例子中,表演的流程顺序是绝对稳定的。不可能先谢幕(Show3)再开场。这个顺序逻辑必须在父类写死,防止子类乱改。
  • 变化点 (Changing):子流程需要变化
    • 具体的表演内容(钻火圈还是骑单车)是变化的。

3. 代码结构 (Code Structure)

图中标注的这三点是实现该模式的“铁律”:

  1. 基类中有骨架流程接口:
    • 通常是一个 Public 非虚函数(如 void Show())。
    • 注意: 为什么是非虚函数?因为我们不希望子类去覆写这个流程!这在 C++ 中有时被称为 NVI (Non-Virtual Interface) 手法的一种变体。
  2. 所有子流程对子类开放并且是虚函数:
    • 通常是 Protected Virtual 函数。
    • Protected:因为这些细节步骤不应该被客户端直接调用(观众不能直接命令海豚“钻火圈”,只能命令它“开始表演”)。
    • Virtual:为了让子类能重写 (Override)。
  3. 多态使用方式:
    • 客户端持有基类指针 ZooShow*,指向子类对象 new DolphinShow
    • 调用 ptr->Show() 时,执行的是父类的流程,但在流程内部调用的 Show1() 却是子类的实现。

4. 符合哪些设计原则?

A. 依赖倒置原则 —— 最核心的设计哲学

图中提到了两点:

  1. 子类扩展时,需要依赖基类的虚函数实现:
    • 通常我们认为“谁调用谁,谁就依赖谁”。但在模板模式中,是父类(高层模块)调用子类(底层模块)的实现。
    • 这就是著名的 “好莱坞原则” (Hollywood Principle):“别给我们打电话,我们会给你打电话。”
    • ZooShow (父类) 是导演,DolphinShow (子类) 是演员。导演控制流程,到点了喊演员上来演,而不是演员指挥导演。
  2. 使用者只依赖接口:
    • main 函数中,我们使用的是 ZooShow* 指针。
    • 使用者根本不需要知道具体是 Dolphin 还是 Lion,也不需要知道内部怎么 PlayGame,只管调用 Show()

B. 封装变化点 (Encapsulate what varies) -> protected

  • 图中关键词: protected
  • 解读: 这是一个非常重要的 C++ 细节。
    • 为什么不是 public 如果 Show1() 是 public,外部用户就可以直接调用 dolphin->Show1(),从而绕过了 Show0 的检查和 PlayGame 环节,打破了算法骨架的完整性。
    • 为什么不是 private 因为 private 子类看不见,没法重写。
    • 所以必须是 protected 这是父类和子类之间的“私密契约”,对外界(main函数)是隐藏的,但对家族内部是开放的。

C. 单一职责原则 (Single Responsibility Principle)

  • 父类 (ZooShow): 只负责制定规则(算法骨架、流程控制)。
  • 子类 (DolphinShow): 只负责执行细节(具体怎么表演)。
  • 两者分工明确,互不干扰。

D. 最小知道原则 (Least Knowledge Principle / Law of Demeter)

  • 解读: 外部调用者(Client)知道得越少越好。
  • 代码体现:
    • 调用者只知道有一个 Show() 方法。
    • 它不知道 Show0 是什么,不知道 PlayGame 里面判断了 expired,也不知道 Show1 具体是干嘛的。
    • 系统的复杂度被封装在类内部,外部接口极其简单。

5. 如何扩展?

这是模板方法模式最大的威力所在:

  1. 实现子类继承基类:
    • class TigerShow : public ZooShow
  2. 复写子流程:
    • override Show1(), override Show2()...
    • 注意: 你完全不需要碰父类的 Show() 函数,也不需要复制粘贴父类的逻辑。
  3. 通过多态调用方式使用:
    • ZooShow* ptr = new TigerShow();
    • ptr->Show();

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询