现在的位置: 首页 > 综合 > 正文

【2013.2.12】上阵父子兵,打仗两模式——Strategy&State

2018年02月19日 ⁄ 综合 ⁄ 共 2667字 ⁄ 字号 评论关闭

// // // // // // // // //

///2013.2.12

// // // // // // // // //

设计模式中很多模式都是非常相像的,

然而在这些模式中公认的最为相近的模式就是Strategy与State,

故此文将两个模式写在一起,

方便读者进行学习与比较。

Strategy模式:


什么地方最常使用Strategy模式呢?

答案是:Strategy(策略类)游戏,哈哈。 :-)


例如战棋类策略游戏,

玩家要决定每回合要攻击,等待,还是使用道具。

每个策略有各自不同的行为,

也不同的逻辑算法

【核心】在不同情况使用(由因子决定)不同的策略来解决问题。

UML图:

因为其使用时机非常明确,

故不做赘述。

要注意的是,

注意在UML图中,

是使用组合的方式来实现Strategy的,

这也是与Template(使用继承)最大的不同点了。

示例代码:

【大致思路】

Strategy模式有两个子类:Move以及Attack,分别代表不同的策略。

Client在构造时传入Strategy不同的实例,

从而具有不同的Do行为(构造后不可修改)。

Strategy.h

#ifndef _STRATEGY_H_
#define _STRATEGY_H_
#include<iostream>

class Strategy
{
public:
	Strategy(){}
	~Strategy(){}

	virtual void Execute() = 0;
};

class Attack:public Strategy
{
public:
	Attack(){}
	~Attack(){}

	virtual void Execute();
};

class Move:public Strategy
{
public:
	Move(){}
	~Move(){}

	virtual void Execute();
};

#endif

strategy.cpp

#include"Strategy.h"

using namespace std;

void Attack::Execute()
{
	cout<<"Attack!"<<endl;
}

void Move::Execute()
{
	cout<<"Move!"<<endl;
}

Client.h

#ifndef _CLIENT_H_
#define _CLIENT_H_
#include"Strategy.h"

class Client
{
private:
	Strategy* strategy;

public:
	Client(Strategy* s);
	~Client(){}

	void Do();
};

#endif

Client.cpp

#include"Client.h"

using namespace std;

Client::Client(Strategy* s)
{
	strategy = s;
}

void Client::Do()
{
	if(strategy == nullptr)
	{
		cout<<"Please initial strategy at first!!!"<<endl;
		return;
	}

	strategy->Execute();
}

main.cpp

#include"Client.h"

int main()
{
	Strategy* attack = new Attack();
	Strategy* move = new Move();

	Client* clientA  = new Client(attack);
	Client* clientB  = new Client(move);

	int i = 0;

	clientA->Do();
	clientB->Do();

	return 0;
}

输出结果:

接下来是State模式:

说起State模式,

就不得不提FSM(有限状态机)了。

众所周知,

在实现AI的时候(不管是游戏还是别的),

目标物体会有不同的状态,

例如游戏里面会有Wait,Move,或是Attack状态。

其实如果只是少数状态的话,

使用switch或if进行罗列也不失为一种好办法。

但是如果状态很多呢?

或是状态与状态之间的逻辑相似,内容不同呢?

这个时候使用if或switch就显得不是那么方便了,

而State模式即是应此而生的啦。

【核心】状态之间实现不相同却具有相似的逻辑,并且可以在不同的状态之间进行灵活切换

注意前半句也是适用于Strategy以及Template的,后半句是State与这两者之间最为主要的区别(亦是其最主要特点)。

UML图:

示例代码:

Client.h

#ifndef _CLIENT_H_
#define _CLIENT_H_
#include"Strategy.h"

class Client
{
private:
	Strategy* strategy;

public:
	Client(){}
	~Client(){}

	void setStrategy(Strategy* s);
	void Do();
};

#endif

Client.cpp

#include"Client.h"

using namespace std;

void Client::setStrategy(Strategy* s)
{
	this->strategy = s;
}

void Client::Do()
{
	if(strategy == nullptr)
	{
		cout<<"Please set strategy at first!!!"<<endl;
		return;
	}

	strategy->Execute();
}

main.cpp

#include"Client.h"

int main()
{
	Client* client  = new Client();

	Strategy* attack = new Attack();
	Strategy* move = new Move();

	int i = 0;

	do
	{
		int rand = std::rand()%2;

		if(rand == 0)
			client->setStrategy(attack);
		else 
			client->setStrategy(move);

		client->Do();

	}while(i++ <10);

	return 0;
}

p.s. Strategy.h与strategy.cpp与Strategy模式完全相同!!!!

输出结果:

【注意事项】

为了作对比,

我尽量将这两个模式涉及到的类及行为进行了统一,

甚至Strategy类及其子类完全没有任何变动。

因此二者的区别很明显地就体现出来了:

State模式可以传入不同的模式实例,

从而达到在运行时改变状态;

然而Strategy模式却无法修改其内部封装的Strategy的实例,

故只能在构造Client时同时初始化此实例。

除此之外,

为了使程序稍微显得有趣一点,

我使用了随机函数来随机指定不同的State(尽管只有两个……)。

抱歉!评论已关闭.