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