• C++设计模式---模板方法模式



    模板方法模式的作用

    在固定步骤确定的情况下,通过多态机制在多个子类中对每个步骤的细节进行差异化实现。

    比如一个到餐馆吃饭的流程:点餐(粤菜,鲁菜)->吃饭->结账(现金,微信),不同的人在各个环节都有不同的动作,但流程是一样的,此时就可以采用多态实现这种差异化。


    具体的定义方式

    父类中定义了一个操作中的算法的骨架(稳定部分),而将一些步骤延迟到子类中去实现(比如父类中定义虚函数,子类中重写虚函数)。

    通过这样的方式,达到在整体稳定的情况下,能够产生一些变化的目的。

    模板方法模式也被认为导致了一种反向控制结构,这种结构也被称为好莱坞法则,也就是不用来调用我,我会去调用你的,即父类调用了子类的函数。


    具体的应用情景

    假设你现在是一名游戏程序员,游戏策划想让你实现一个战士类,这个类有生命、魔法、攻击力等属性,并且有一个“燃烧的技能”,能够让所有敌人掉血,但是自己也会掉血,你可以这样实现:

    #include
    using namespace std;
    
    class Warrior {
    public:
    	Warrior(int life,int magic,int attack)
    		:m_life(life)
    		,m_magic(magic)
    		,m_attack(attack){}
    
    	//燃烧技能
    	void JN_Burn()
    	{
    		cout << "让所有敌人每人失去500生命,相关逻辑代码略过。。。" << endl;
    		cout << "主角自身失去300生命" << endl;
    		m_life -= 300;
    		cout << "播放燃烧技能的动画" << endl;
    	}
    private:
    	//角色属性
    	int m_life;//生命
    	int m_magic;//魔法值
    	int m_attack;//攻击力
    };
    
    int main()
    {
    	Warrior morleobj(1000, 0, 200);
    	morleobj.JN_Burn();//释放燃烧技能
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    现在游戏策划又想让你实现一个“法师”类,这个类和战士类的成员属性一样,唯一的不同是“燃烧”技能不会让自己掉血而是掉魔法值。并且策划告诉你,每个类都有一个“燃烧”技能。

    你发现“法师”类和“战士”类大部分代码是相同的,那此时你直接实现一个“战斗者”的抽象类,让“战士”类和“法师”类继承“战斗者”类。

    #include
    using namespace std;
    //抽象类
    class Fighter {
    public:
    	Fighter(int life, int magic, int attack)
    		:m_life(life)
    		, m_magic(magic)
    		, m_attack(attack) {}
    	virtual ~Fighter() {}
    
    	//燃烧技能
    	void JN_Burn()
    	{
    		effect_enemy();//对敌人产生影响
    		effect_self();//对自身产生影响
    		play_effect();//播放“燃烧”技能特效,由于经费不足,这个技能特效所有类都相同
    	}
    private:
    	virtual void effect_enemy() = 0;
    	virtual void effect_self() = 0;
    	void play_effect() 
    	{
    		//实现“燃烧”特效
    		cout << "播放燃烧技能的特效,由于经费不足,这个技能特效所有类都相同,不需要虚函数" << endl;
    	}
    
    protected://因为可能会被子类访问,所以不使用private
    	//角色属性
    	int m_life;//生命
    	int m_magic;//魔法值
    	int m_attack;//攻击力
    };
    //战士类
    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;
    	}
    };
    //法师类
    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;
    	}
    };
    
    int main()
    {
    	Fighter* p1 = new F_Warrior(1000, 0, 200);
    	Fighter* p2 = new F_Mage(5000, 500, 300);
    
    	//战士和法师释放燃烧技能
    	p1->JN_Burn();
    	cout << "----------------" << endl;
    	p2->JN_Burn();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    在这里插入图片描述

    上面的代码已经引入了“模板方法模式”,不同的类通过父类指针调用同一个函数JN_Burn,由于多态机制,子类重写了JN_Burn中的虚函数。
    JN_Burn这个函数中调用的函数数量和顺序总是固定的,因此这个函数就可以称为“模板”。

    至此不同的子类产生了不同的效果,但所有子类的执行流程完全相同。
    在这里插入图片描述

  • 相关阅读:
    echarts折线图的symbol自定义样式
    BioVendor游离轻链(κ和λ)Elisa 试剂盒检测步骤
    Perl中捕获警告信息、异常信息并写入日志详解
    位运算 离散化 区间和算法
    一个完整的项目测试方案流程应该是什么样的?
    linux中的vim工具
    【开源项目】libfaketime安装、使用——小白教程
    Python3操作文件系列(一):判断文件|目录是否存在三种方式
    C++ 虚函数
    你要的react+ts最佳实践指南
  • 原文地址:https://blog.csdn.net/qq_52670477/article/details/126612979