学以致用C++设计模式 之 “状态模式”

举报
看,未来 发表于 2020/12/29 23:46:07 2020/12/29
【摘要】 文章目录 从DFA讲起游戏角色什么是状态模式状态模式的应用优点:缺点: 从DFA讲起 何为DFA?确定的有穷状态机。这里 看完上面那篇博客,就明白状态机还挺好用的。 那么现在,转场。 游戏角色 要开发一款游戏,咱负责的模块是处理游戏角色属性框架的搭建,目前已知角色有:坦克、法师、射手,他们都有属性:血量、物攻、物抗、法攻、法抗、角色...

在这里插入图片描述

从DFA讲起

何为DFA?确定的有穷状态机。这里

看完上面那篇博客,就明白状态机还挺好用的。
那么现在,转场。

游戏角色

要开发一款游戏,咱负责的模块是处理游戏角色属性框架的搭建,目前已知角色有:坦克、法师、射手,他们都有属性:血量、物攻、物抗、法攻、法抗、角色转换技能。

同样,可以采用自动机的方式来进行处理:

坦克 法师 射手
坦克 - 双抗-,法攻+ 双抗-,物攻+
法师 双抗+,法攻- - 物攻+,法攻-
射手 双抗+,物攻- 物攻-,法攻+ -

也挺好办的,就这样封装好了。

但是,这毕竟是C语言的方式,面向过程,如果我要拓展,加俩新角色进去呢?加个近战战士,怎么办?把写好的代码拆了重写?那明天再加个辅助进去,再重写?

既然学了面向对象,那就用面向对象的方式来解决这类问题:将每种状态封装成类,然后该怎么办就不用我多说了。

类怎么设计呢?看这样好不好:

class 坦克{
private:
	int 血量;
	int 物攻;
	int	物抗;
	int 法攻;
	int 法抗;
public:
	void 攻击();
	void 防守();
	void 技能();
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

可还行?
然后场景类就这样:

int main(){

	class* 坦克兵 = new 坦克();
	class* 魔法师 = new 法师();
	class* 狙击手 = new 射手();
	
//被人打了,用坦克
	坦克兵->防守();

//要打消耗,用法师
	魔法师->攻击();

//敌人要跑,用射手
	狙击手->技能();

···
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

这样始终是零散,疏于管教。而且,并不能实现自动啊,顶多就是个手动状态机。
那怎么弄哦?将前边的DFA再看看,再配上责任链的思想,想想就知道该来了父类,然后每个子类中自己管理自己的状态,再维护一条状态链表,实现有穷的自动状态机(C++状态模式版)。

你看这样可好?

class 状态基类{
private:
	string 当前状态;
	状态基类* 下一状态;
public:
	virtual void 攻击();
	virtual void 防守();
	virtual void 技能();
	void setState(string 状态){this->当前状态 = 状态;}
	void setNextNode(状态基类* 下一状态){this->下一状态 = 下一状态;};
	状态基类* 遍历状态(string 目标状态){
		if(this->当前状态 == 目标状态) return this;
		else if(this->下一状态 != NULL) 下一状态->遍历状态(目标状态);
		else return NULL;
	}
}

class 坦克:public 状态基类{
public:
	void 攻击(){···}
	void 防守(){···}
	void 技能(){···}
}

···

  
 
  • 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

场景类就这样实现了:

状态基类* 状态1 = new 坦克();
状态基类* 状态2 = new 战士();
状态基类* 状态3 = new 法师();
状态基类* 状态4 = new 射手();

状态基类* 当前状态;

状态1->setState("坦克");
状态2->setState("战士");
状态3->setState("法师");
状态4->setState("射手");


状态1->setNextNode(状态2);
状态2->setNextNode(状态3);
状态3->setNextNode(状态4);

//被人打了
当前状态 = 状态1->遍历状态(坦克);
当前状态->防守();

//要打消耗,用法师
当前状态 = 状态1->遍历状态(法师);
当前状态->攻击();

//敌人要跑,用射手
当前状态 = 状态1->遍历状态(射手);
当前状态->技能();

//中埋伏了,换战士
当前状态 = 状态1->遍历状态(战士);
当前状态->攻击();
当前状态->防守();
当前状态->放技能();


  
 
  • 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

这样连轴转。


什么是状态模式

当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其种类。

状态模式的核心是封装,状态的变更引起了行为的变更,从外部看起来就好像这个对象对应的类发生了改变一样。

状态模式的应用

优点:

结构清晰、遵循设计原则、封装性好

缺点:

要避免状态过多。

在这里插入图片描述

文章来源: lion-wu.blog.csdn.net,作者:看,未来,版权归原作者所有,如需转载,请联系作者。

原文链接:lion-wu.blog.csdn.net/article/details/107081209

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。