C++设计模式系列之三行为型模式

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;
}




未完待续...

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值