C++设计模式系列之三举动型模式
C++设计模式系列之三行为型模式
Memento.hpp:

1.Iterator模式
Iterator.hpp:
#ifndef _ITERATOR_HPP #define _ITERATOR_HPP #include <vector> struct Player { int mPID; }; class PlayerManager { public: PlayerManager() :mBeginIter( &mPlayers ) {} ~PlayerManager() {} struct Iterator { Iterator() { mref = nullptr; mIndex = 0; } Iterator( std::vector< Player* > *ref ) { mref = ref; mIndex = 0; } Iterator( const Iterator &other ) { mref = other.mref; mIndex = other.mIndex; } Iterator& operator = ( const Iterator &other ) { if( this == &other ) { return *this; } mIndex = other.mIndex; mref = other.mref; } Iterator& operator ++(int idx) { return operator ++(); } Iterator& operator ++() { ++mIndex; return *this; } bool operator !=( const Iterator &other ) { return mIndex != other.mIndex; } Player* operator *() { return (*mref)[ mIndex ]; } Player** operator ->() { return &(*mref)[ mIndex ]; } int mIndex; std::vector< Player* > *mref; }; void AddPlayer( Player *pPlayer ) { mPlayers.push_back( pPlayer ); mEndIter.mIndex = mPlayers.size(); } Iterator Begin() { return mBeginIter; } Iterator End() { return mEndIter; } private: std::vector< Player* > mPlayers; Iterator mBeginIter; Iterator mEndIter; }; #endif
Main.cpp:
#include "Iterator.hpp" //作用:封装对内部复杂聚合类的元素访问,并且可以丰富扩展自定义功能,典型例子stl容器的iterator //例子简单实现了部分功能理解iterator模式 int main() { Player *p; PlayerManager* ppm = new PlayerManager; for( int i = 0; i < 3; ++i ) { p = new Player; p->mPID = i; ppm->AddPlayer( p ); } for( PlayerManager::Iterator i = ppm->Begin(); i != ppm->End(); ++i ) { //迭代器访问数据 int id = (*i)->mPID; delete *i; } delete ppm; return 0; }
2.Template模式
Template.hpp:
#ifndef _TEMPLATE_HPP #define _TEMPLATE_HPP class TopFrame { public: TopFrame(){} virtual ~TopFrame(){} void FrameMethod() { //注意这里,非虚方法封装虚方法,凡是这种行为,即是template模式 //目的明确,FrameMethod对外,SubMethod1和SubMethod2在顶层对内 //当然有时候,我们无意中也会写出设计模式来只不过我们不知道罢了 SubMethod1(); SubMethod2(); } protected: virtual void SubMethod1() = 0; virtual void SubMethod2() = 0; }; class Sub1 : public TopFrame { public: Sub1(){} ~Sub1(){} void SubMethod1(){} void SubMethod2(){} }; class Sub2 : public TopFrame { public: Sub2(){} ~Sub2(){} void SubMethod1(){} void SubMethod2(){} }; #endif
Main.cpp:
//作用:抽象顶层封装逻辑方法或者通用放,具体算法细节延迟到子类实现 //客户程序员只关心public的方法即本例子中的FrameMethod对外方法 //对外接口FrameMethod在顶层调用在该类中虚方法,封装了具体过程而 //不在关心子类方法 int main() { TopFrame *p1 = new Sub1; TopFrame *p2 = new Sub2; p1->FrameMethod(); p2->FrameMethod(); delete p1; delete p2; return 0; }
3.Strategy模式
Strategy.hpp:
#ifndef _STRATEGY_HPP #define _STRATEGY_HPP class Scene { public: virtual ~Scene(){} virtual void Init() = 0; virtual void Update() = 0; virtual void Render() = 0; virtual void Destroy() = 0; }; class MenuScene : public Scene { public: MenuScene(){} ~MenuScene(){} void Init(){} void Update(){} void Render(){} void Destroy(){} }; class LoadingScene : public Scene { public: LoadingScene(){} ~LoadingScene(){} void Init(){} void Update(){} void Render(){} void Destroy(){} }; class GameScene : public Scene { public: GameScene(){} ~GameScene(){} void Init(){} void Update(){} void Render(){} void Destroy(){} }; class App { public: App() { mp = nullptr; } ~App() { if( nullptr != mp ) { delete mp; } } void SwitchScene( Scene *p ) { if(mp == p) { return; } if( nullptr != mp ) { mp->Destroy(); } mp = p; mp->Init(); } void Run() { if(nullptr == mp) { return; } mp->Update(); mp->Render(); } private: Scene *mp; }; #endif
Main.cpp:
//作用:重在策略,切换不同的方法行为 //对象行为相同,但实现不同,而且还有可能发送互相替换 //说白了就是对象之前切换然后调用行为方法 //典型例子为场景切换,或者有些游戏中的,武器切换 int main() { Scene *p1 = new MenuScene; Scene *p2 = new LoadingScene; Scene *p3 = new GameScene; App *pa = new App;//简单模拟场景管理 //切换到菜单场景 pa->SwitchScene( p1 ); //调用菜单场景逻辑和渲染( 这里只是简单模拟场景切换 ) pa->Run(); //切换到资源加载场景 pa->SwitchScene( p2 ); pa->Run(); //切换到游戏场景 pa->SwitchScene( p3 ); pa->Run(); delete pa; delete p3; delete p2; delete p1; return 0; }
4.State模式
State.hpp:
#ifndef _STATE_HPP #define _STATE_HPP class M16_Rifle; //抽象状态 class M16_State { protected: M16_State(){} public: virtual ~M16_State(){} //开火时的音效 virtual void FireAudio() = 0; //调整影响枪的火力 virtual void AdjustPower( M16_Rifle *pM16 ) = 0; }; class M16_MufflerState : public M16_State { public: M16_MufflerState(){} ~M16_MufflerState(){} private: void FireAudio() { //播放消音开火音效 } void AdjustPower( M16_Rifle *pM16 ) { //消音状态下火力减少 //pM16->mPower -= 10; } }; class M16_NormalState : public M16_State { public: M16_NormalState(){} ~M16_NormalState(){} private: void FireAudio() { //播放非消音开火音效 } void AdjustPower( M16_Rifle *pM16 ) { //非消音状态下火力回复 //pM16->mPower += 10; } }; class M16_Rifle { public: friend class M16_MufflerState; friend class M16_NormalState; M16_Rifle() { mpMullfer = new M16_MufflerState; mpNormal = new M16_NormalState; mpCurr = mpNormal; mPower = 50; } ~M16_Rifle() { delete mpMullfer; delete mpNormal; } void Fire() { mpCurr->FireAudio(); //... } //消音和不消音来回切换 void SwitchFireMode() { mpCurr = mpCurr == mpNormal ? mpMullfer : mpNormal; mpCurr->AdjustPower( this ); } private: M16_State *mpMullfer; M16_State *mpNormal; M16_State *mpCurr; int mPower; }; #endif
Main.cpp:
//作用:从对象内部改变状态,控制对象行为避免外部switch if else 嵌套结构 //CS游戏中警察M-16这种自动步枪就有两种状态 //普通状态和消音器状态 //有人说用bool值就行了,如果是3种以上且有嵌套的复杂状态呢? int main() { M16_Rifle *pM16 = new M16_Rifle; //默认非消音 pM16->Fire(); //切换消音 pM16->SwitchFireMode(); pM16->Fire(); //切换非消音 pM16->SwitchFireMode(); pM16->Fire(); delete pM16; return 0; }
5.Observer模式
Observer.hpp:
#ifndef _OBSERVER_HPP #define _OBSERVER_HPP #include <set> typedef unsigned int u32; //以星际争霸2游戏中人族科技建筑为例 template <typename T> class IObserver; //被观察者 template< typename T > class IObservable { public: IObservable(){} virtual ~IObservable(){} virtual void AddObserver( IObserver< T > *pObserver ) = 0; virtual void DeleteObserver( IObserver< T > *pObserver ) = 0; virtual void NotifyObservers( T context ) = 0; }; //观察者 template< typename T > class IObserver { public: IObserver(){} virtual ~IObserver(){} virtual void Update( T context ) = 0; }; //晶矿 class Crystal : public IObservable< u32 > { public: Crystal(){} ~Crystal(){} virtual void AddObserver( IObserver<u32> *pObserver ) { mObservers.insert( pObserver ); } virtual void DeleteObserver( IObserver<u32> *pObserver ) { mObservers.erase( pObserver ); } virtual void NotifyObservers( u32 context ) { for( auto i = mObservers.begin(); i != mObservers.end(); ++i ) { (*i)->Update( context ); } } private: std::set< IObserver<u32>* > mObservers; }; //重工厂 class Factory : public IObserver< u32 > { public: void Update( u32 context ) { if( context > 200 ) { //可建造重工厂 } } }; //兵营 class Barracks : public IObserver< u32 > { public: void Update( u32 content ) { if( content > 150 ) { //可建造兵营 } } }; #endif
Main.cpp:
#include "Observer.hpp" //作用:被观察者可以注册可以观察他的观察者,被观察者出发相应的事件或者状态 //观察者会收到相应的通知数据,根据数据做出不同的处理 //这个例子可能写的比较特殊理解这种思想即可 int main() { //晶矿 Crystal *pCrystal = new Crystal; //重工 Factory *pF = new Factory; //兵营 Barracks *pB = new Barracks; pCrystal->AddObserver( pF ); pCrystal->AddObserver( pB ); u32 Count = 1000; //采矿1000 pCrystal->NotifyObservers( Count ); delete pB; delete pF; delete pCrystal; return 0; }
6.Command模式
Command.hpp:
#ifndef _COMMAND_HPP #define _COMMAND_HPP //Command模式使用的范围就太多了 //例如星际争霸中人族SCV的控制面板( 移动、攻击、巡逻、采矿、停止... ) class Command { public: Command(){} virtual ~Command(){} virtual void Execute() = 0; }; class SCV { public: SCV(){} ~SCV(){} void Move( int x, int y ){} void Attack( int x, int y ){} void Round( int x, int y ){} void Mining( int x, int y ){} void Stop(){} }; //将行为进行封装 class MoveCommand : public Command { public: MoveCommand(){} ~MoveCommand(){} MoveCommand( SCV *p, int x, int y ) { mp = p; mx = x; my = y; } void Execute() { mp->Move( mx, my ); } private: SCV *mp; int mx; int my; }; class AttackCommand : public Command { public: AttackCommand(){} ~AttackCommand(){} AttackCommand( SCV *p, int x, int y ) { mp = p; mx = x; my = y; } void Execute() { mp->Attack( mx, my ); } private: SCV *mp; int mx; int my; }; class RoundCommand : public Command { public: RoundCommand(){} ~RoundCommand(){} RoundCommand( SCV *p, int x, int y ) { mp = p; mx = x; my = y; } void Execute() { mp->Round( mx, my ); } private: SCV *mp; int mx; int my; }; class MiningCommand : public Command { public: MiningCommand(){} ~MiningCommand(){} MiningCommand( SCV *p, int x, int y ) { mp = p; mx = x; my = y; } void Execute() { mp->Mining( mx, my ); } private: SCV *mp; int mx; int my; }; class StopCommand : public Command { public: StopCommand(){} ~StopCommand(){} StopCommand( SCV *p ) { mp = p; } void Execute() { mp->Stop(); } private: SCV *mp; }; //命令者只知道接口,具体如何实现他不知道 class Commander { public: Commander( Command *pCmdMove, Command *pCmdAttack, Command *pCmdRound, Command *pCmdMining, Command *pCmdStop ) { mpCmdMove = pCmdMove; mpCmdAttack = pCmdAttack; mpCmdRound = pCmdRound; mpCmdMining = pCmdMining; mpCmdStop = pCmdStop; } ~Commander() {} void Move() { mpCmdMove->Execute(); } void Attack() { mpCmdAttack->Execute(); } void Round() { mpCmdRound->Execute(); } void Mining() { mpCmdMining->Execute(); } void Stop() { mpCmdStop->Execute(); } private: Command *mpCmdMove; Command *mpCmdAttack; Command *mpCmdRound; Command *mpCmdMining; Command *mpCmdStop; }; #endif
Main.cpp:
#include "Command.hpp" //作用:将高层命令与行为解耦,特别适合对象行为固定的情况下非常方便 //某些情况下特别适合undo 和 redo 因为Command模式会储存行为的数据 //将他们放入栈内....push pop...本例不讨论 //例子只是让人更好理解而已,写的不是太恰当 //不想举一些跟程序无关的例子 int main() { SCV *pScv = new SCV; //移动命令 MoveCommand *pCmdMove = new MoveCommand( pScv, 0, 0 ); //攻击命令 AttackCommand *pCmdAtt = new AttackCommand( pScv, 0, 0 ); //巡逻命令 RoundCommand *pCmdRound = new RoundCommand( pScv, 0, 0 ); //采矿命令 MiningCommand *pCmdMining = new MiningCommand( pScv, 0, 0 ); //停止命令 StopCommand *pCmdStop = new StopCommand( pScv ); //指挥官面板 Commander *pCmder = new Commander( pCmdMove, pCmdAtt, pCmdRound, pCmdMining, pCmdStop ); pCmder->Move(); pCmder->Attack(); pCmder->Round(); pCmder->Mining(); pCmder->Stop(); delete pCmder; delete pCmdStop; delete pCmdMining; delete pCmdRound; delete pCmdAtt; delete pCmdMove; delete pScv; return 0; }
7.Memento模式
Memento.hpp:
#ifndef _MEMENTO_HPP #define _MEMENTO_HPP #include <memory> template< typename T > class Memento { public: Memento( T *pt ) { mpt = new T( *pt ); } ~Memento() { delete mpt; mpt = nullptr; } T* GetData() { return mpt; } private: T *mpt; }; class Setting { public: Setting() { mData1 = mData2 = mData3 = 0; mp = new char[ 32 ]; strcpy_s( mp, 32, "default" ); } Setting( const Setting &other ) { mData1 = other.mData1; mData2 = other.mData2; mData3 = other.mData3; mp = new char[ 32 ]; strcpy_s( mp, 32, other.mp ); } ~Setting() { delete mp; mp = nullptr; } Memento< Setting >* CreateRestore() { return new Memento< Setting >( this ); } void Restore( Memento< Setting > *p ) { auto px = p->GetData(); mData1 = px->mData1; mData2 = px->mData2; mData3 = px->mData3; strcpy_s( mp, 32, px->mp ); } void SetData( int d1, int d2, int d3, char *p ) { mData1 = d1; mData2 = d2; mData3 = d3; strcpy_s( mp, 32, p ); } void print() { printf( "%d\n", mData1 ); printf( "%d\n", mData2 ); printf( "%d\n", mData3 ); printf( "%s\n\n", mp ); } private: int mData1; int mData2; int mData3; char *mp; }; #endif
Main.cpp
#include "Memento.hpp" //作用:记录对象数据的快照,在后续需要的情况下根据快照重新还原对象数据 //例如我们常用的一些设置面板,参数繁多,很容易设置错误,当设置错误时 //通过一种手段还原到最初的默认数据 int main() { auto *pSet = new Setting; //打印一下默认的设置数据 pSet->print(); //记录一下默认设置数据还原点 auto *pDefPoint = pSet->CreateRestore(); //设置新设置数据 pSet->SetData( 102, 103, 32, "new data1" ); pSet->print(); //创建记录新的还原点 auto *pNewPoint = pSet->CreateRestore(); //设置新的设置数据 pSet->SetData( 32, 1, 3, "new data2" ); pSet->print(); //创建新的还原点2 auto *pNewPoint2 = pSet->CreateRestore(); //我后悔了想要恢复的默认数据 pSet->Restore( pDefPoint ); pSet->print(); //我后悔了想要恢复到第一次设置新数据哪里 pSet->Restore( pNewPoint ); pSet->print(); //我后悔了还是恢复到最后一次的吧 pSet->Restore( pNewPoint2 ); pSet->print(); delete pNewPoint2; delete pNewPoint; delete pDefPoint; delete pSet; return 0; }
未完待续...