c/c++设计模式--模板方法模式
模板方法模式是一种行为设计模式,它定义了一个算法的骨架,并允许子类在不改变该算法结构的情况下重写算法的特定步骤。这种模式属于行为型模式,它通过将具体实现延迟到子类来提供算法的变化点。
在模板方法模式中,通常有两种角色:
-
抽象类(Abstract Class):定义了一个算法的骨架,其中包含了一系列抽象方法或者受保护的方法,这些方法是算法的各个步骤。抽象类可以包含一个模板方法,该方法定义了算法的结构,通常是一个具体方法,它调用了算法中的各个步骤。这些步骤可以是抽象方法,由子类去实现,也可以是具体方法,提供了默认实现。
-
具体子类(Concrete Subclasses):实现了抽象类中定义的抽象方法,以提供算法的具体实现。这些具体子类通常只需要实现抽象方法中与特定实现相关的部分,而不需要改变算法的整体结构。
模板方法模式的核心思想是将算法的不变部分封装在父类中,将可变部分留给子类去实现,从而实现了代码的重用和扩展。这种模式常用于以下场景:
- 当多个类中有相似的算法,并且这些算法中的部分步骤是固定不变的,而其他部分需要根据具体情况进行实现时,可以使用模板方法模式。
- 当需要提供一个通用的算法框架,而具体的步骤实现可能会随着不同情况而变化时,可以使用模板方法模式。
举个例子,假设有一个制作饮料的模板方法,其中包括了泡茶和泡咖啡两个步骤,但是具体的泡茶和泡咖啡的步骤可能有所不同,可以使用模板方法模式来实现这个过程
下面是一个简单的 C++ 示例,演示了模板方法模式的实现。假设我们有一个制作饮料的过程,包括煮水、冲泡、倒入杯子和添加调料。我们可以使用模板方法模式来定义这个过程的框架,并在子类中实现具体的步骤。
#include <iostream> // 抽象类 - 制作饮料 class Beverage { public: // 模板方法 - 制作饮料的整个过程 void prepareBeverage() { boilWater(); brew(); pourInCup(); addCondiments(); } // 具体步骤 - 煮水 void boilWater() { std::cout << "Boiling water" << std::endl; } // 抽象步骤 - 冲泡 virtual void brew() = 0; // 具体步骤 - 倒入杯子 void pourInCup() { std::cout << "Pouring into cup" << std::endl; } // 抽象步骤 - 添加调料 virtual void addCondiments() = 0; }; // 具体子类 - 制作茶 class Tea : public Beverage { public: // 实现具体步骤 - 冲泡茶 void brew() override { std::cout << "Steeping the tea" << std::endl; } // 实现具体步骤 - 添加柠檬 void addCondiments() override { std::cout << "Adding lemon" << std::endl; } }; // 具体子类 - 制作咖啡 class Coffee : public Beverage { public: // 实现具体步骤 - 冲泡咖啡 void brew() override { std::cout << "Dripping coffee through filter" << std::endl; } // 实现具体步骤 - 添加糖和牛奶 void addCondiments() override { std::cout << "Adding sugar and milk" << std::endl; } }; int main() { Beverage* tea = new Tea(); Beverage* coffee = new Coffee(); std::cout << "Making tea..." << std::endl; tea->prepareBeverage(); std::cout << "\nMaking coffee..." << std::endl; coffee->prepareBeverage(); delete tea; delete coffee; return 0; }
namespace _nmsp2 { //战斗者父类 class Fighter { public: Fighter(int life, int magic, int attack) :m_life(life), m_magic(magic), m_attack(attack) {} virtual ~Fighter() {} //做父类时析构函数应该为虚函数 //对主角自身会产生影响,对敌人会产生影响。 //分析:对敌人产生影响,有函数effect_enemy。对主角自身产生影响,有函数effect_self。播放技能play_effect函数。 void JN_Burn() //技能“燃烧”,模板方法 { if (canUseJN() == false) //如果不能使用该技能,则直接返回 return; effect_enemy(); //对敌人产生的影响 effect_self(); //对主角自身产生的影响 play_effect(); //播放技能“燃烧”的技能特效 } private: virtual void effect_enemy() {} //函数体为空,表示啥也不做,如果要求必须在子类中重新实现该虚函数,则可以将该函数写成纯虚函数。 virtual void effect_self() {} void play_effect() { cout << "播放技能\"燃烧\"的技能特效给玩家看" << endl; //所有主角播放的技能特效都相同,因此不用写成一个虚函数并在子类中实现技能特效的播放。 } virtual bool canUseJN() = 0; //判断是否能使用技能“燃烧”,这是个纯虚函数声明,子类中必须重新实现canUseJN。 protected: //可能被子类访问,所以用protected修饰 //角色属性 int m_life; //生命值 int m_magic; //魔法值 int m_attack; //攻击力 }; //------------------------- //“战士”类,父类为Fighter class F_Warrior :public Fighter { public: F_Warrior(int life, int magic, int attack) :Fighter(life,magic,attack) {} private: //对敌人产生的影响 virtual void effect_enemy() { cout << "战士主角_让所有敌人每人失去500点生命,相关逻辑代码这里略......" << endl; } //对主角自身产生的影响 virtual void effect_self() { cout << "战士主角_自身失去300点生命值" << endl; m_life -= 300; } virtual bool canUseJN() { if (m_life < 300) //生命值不够300点,不能使用技能“燃烧” return false; return true; } }; //------------------------- //“法师”类,父类为Fighter class F_Mage :public Fighter { public: F_Mage(int life, int magic, int attack) :Fighter(life, magic, attack) {} private: //对敌人产生的影响 virtual void effect_enemy() { cout << "法师主角_让所有敌人每人失去650点生命,相关逻辑代码这里略......" << endl; } //对主角自身产生的影响 virtual void effect_self() { cout << "法师主角_自身失去100点魔法值" << endl; m_magic -= 100; } virtual bool canUseJN() { if (m_magic < 100) //魔法值不够100点,不能使用技能“燃烧” return false; return true; } }; } int main() { /* _nmsp2::Fighter* prole_war = new _nmsp2::F_Warrior(1000, 0, 200); //创建战士主角,注意这里是父类指针指向子类对象以利用多态特性。 prole_war->JN_Burn(); //战士主角释放“燃烧”技能,调用的是F_Warrior类的effect_enemy和effect_self。 cout << "---------------------------" << endl; //分割线,以便更醒目的显示信息 _nmsp2::Fighter* prole_mag = new _nmsp2::F_Mage(800,200, 300); //创建法师主角,注意这里是父类指针指向子类对象以利用多态特性。 prole_mag->JN_Burn(); //法师主角释放“燃烧”技能 //释放资源 delete prole_war; delete prole_mag; */ ////早绑定 //_nmsp2::F_Warrior role_war(1000, 0, 200); //role_war.JN_Burn(); //早绑定 _nmsp2::Fighter* prole_war2 = new _nmsp2::F_Warrior(50, 0, 200);//创建生命值只有50的战士主角 prole_war2->JN_Burn(); //该战士无法成功释放“燃烧”技能,不输出任何结果。 //钩子方法 delete prole_war2; }
