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


模板方法模式的作用

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

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


具体的定义方式

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

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

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


具体的应用情景

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

#include<iostream>
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();//释放燃烧技能
}

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

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

#include<iostream>
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();
}

在这里插入图片描述

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

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今天也要写bug、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值