// // // // // // // // //
///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(尽管只有两个……)。