1. 程式人生 > >C++設計模式系列之二結構型模式

C++設計模式系列之二結構型模式

1.Adapter模式

Adapter.hpp:

#ifndef _ADAPTER_HPP
#define _ADAPTER_HPP



//第三方庫
namespace ThirdPartyNameSpace
{
	class ThirdPartyClass
	{
		public:
			ThirdPartyClass(){}
			~ThirdPartyClass(){}
			void ThirdPartyMethod(){}
	};
};

//我們內部定義好的介面
struct IMethod
{
	virtual void Method() = 0;
};

//內部實現的介面子類
class CustomMethod : public IMethod
{
	public:

		void Method(){}
};

//外部第三方適用我們配器實現介面統一
class ThirdPartyAdapter : public IMethod
{
	public:
		ThirdPartyAdapter( ThirdPartyNameSpace::ThirdPartyClass *p )
		{
			mp = p;
		}
		~ThirdPartyAdapter()
		{}

		void Method()
		{
			mp->ThirdPartyMethod();
		}
	private:

		ThirdPartyNameSpace::ThirdPartyClass *mp;
};

#endif

Main.cpp:

#include "Adapter.hpp"

////作用:引用的第三方庫方法根現有的介面不一致時,通過中間進行轉換將介面保持一致( 記住這種思想即可,其實如何實現你可以自己定義 )
////缺點:當介面函式很多時,中間層不得不每一個都去實現一次,哪怕非純虛方法,到時候
////中間層繼承的介面暴露許多無用方法,這樣很容易出錯,感覺其實adapter是折中的方案
////既然選擇第三方庫了,那麼專案立項的時候就要考慮進來,合理定義介面,如果是後期加入,
////第三方庫一般都是獨立的庫,和現有介面關係不是太大,即便是有關係,也可以通過其他的方案來解決
////Adapter模式的特殊性比較強( 個人觀點,不要為了設計模式而設計模式 )
//
int main()
{
	//內部實現的方案1
	IMethod *p = new CustomMethod;

	p->Method();

	//外部第三方庫實現的方案2
	ThirdPartyNameSpace::ThirdPartyClass *ptp = new ThirdPartyNameSpace::ThirdPartyClass;
	//給內部介面卡
	IMethod *p2 = new ThirdPartyAdapter( ptp );

	//廢了這麼大勁只是為了介面一致( 強烈建議自己實現滿足自己專案的解決方案,有這種思想即是設計模式,當然如果該例子滿足最好 )
	p2->Method();

	delete p2;
	delete ptp;
	delete p;

	return 0;
}

2.Facade模式

Facade.hpp:

#ifndef _FACADE_HPP
#define _FACADE_HPP


//注意A,B,C,D 系統之間沒有直接的關係
class ASystem
{
	public:

		ASystem(){}

		~ASystem(){}

		void DoSomething(){}
};

class BSystem
{
	public:

		BSystem(){}

		~BSystem(){}

		void DoSomething(){}
};

class CSystem
{
public:

	CSystem(){}

	~CSystem(){}

	void DoSomething(){}
};

class DSystem
{
public:

	DSystem(){}

	~DSystem(){}

	void DoSomething(){}
};


//測試ab系統模組
class TestAB
{
	public:

		TestAB()
		{
			mpa = new ASystem;
			mpb = new BSystem;
		}
		
		virtual ~TestAB()
		{
			delete mpa;
			delete mpb;
		}

		//外部只關心呼叫Test方法,A,B系統內部我們不關心,這裡只做聚合功能模組
		void Test()
		{
			mpa->DoSomething();
			mpb->DoSomething();
		}

	private:

		ASystem *mpa;
		BSystem *mpb;
};

//測試cd系統模組
class TestCD
{
public:

	TestCD()
	{
		mpc = new CSystem;
		mpd = new DSystem;
	}

	virtual ~TestCD()
	{
		delete mpc;
		delete mpd;
	}

	void Test()
	{
		mpc->DoSomething();
		mpd->DoSomething();
	}

private:

	CSystem *mpc;
	DSystem *mpd;
};

#endif

Main.cpp:

#include "Facade.hpp"

//作用:將我們實現的各類物件系統,抽取出來並且封裝聚合在一個類中完成特定的功能
//記住這種思想即可,將各個功能類封裝在另一個類中,通過這個聚合類,完成某種高階呼叫

int main()
{
	//例如測試AB系統,我們將AB封裝在TestAB用來測試A和B的呼叫情況外部只需要呼叫一個介面即可,不關心A,B的底層實現
	//那麼TestAB就是A和B的聚合組合,我們稱之為Facade模式
	TestAB *ptab = new TestAB;

	//理由同上
	TestCD *ptcd = new TestCD;

	ptab->Test();

	ptcd->Test();

	delete ptcd;

	delete ptab;

	return 0;
}


3.Proxy模式

Proxy.hpp:

#ifndef _PROXY_HPP
#define _PROXY_HPP
#include <string>

typedef char c8;
typedef const char* cc8p;

//網路代理為典型例子( 包括但不限於例子 )
class Proxy
{
public:

	Proxy(){}

	~Proxy(){}

	//請求代理
	void ProxyLogin(
		cc8p pUsr,
		cc8p pPwd,
		cc8p pProxyIP,
		int ProxyPort,
		cc8p pProxyUsr,
		cc8p pProxyPwd,
		cc8p pTargetIp,
		int TargetPort
		){}

	//代理伺服器回傳資料
	void OnProxyRecv( void *p ){}
};

class LoginUI
{
	public:
		LoginUI(){}
		~LoginUI(){}
		void OnClickedLoginBtn()
		{
			cc8p pUsr = "test001";
			cc8p pPwd = "123456";
			strcpy( mUsr, pUsr );
			strcpy( mPwd, pPwd );
		}
		c8 mUsr[ 16 ];
		c8 mPwd[ 16 ];
};



#endif

Main.cpp:

#include "Proxy.hpp"

//作用:特定的功能委託或者轉交給其他物件完成,我們稱之為proxy代理模式
//例如:(智慧指標委託管理物件生命週期,智慧鎖委託管理鎖物件的鎖定和解鎖,或者其他大部分非同步呼叫的過程)

//下面模擬網路上最常用的網路代理
int main()
{
	//登陸使用者介面UI
	LoginUI *pUsrInterface = new LoginUI;

	//模擬使用者點選登陸,得到輸入的賬號和密碼
	pUsrInterface->OnClickedLoginBtn();

	//OK本地網路太卡了我們通過代理伺服器連線遊戲登陸服
	Proxy *pProxy = new Proxy;

	pProxy->ProxyLogin(
		pUsrInterface->mUsr,				//使用者名稱資料
		pUsrInterface->mPwd,				//使用者密碼
		"xxx.xxx.xxx.xxx",				//代理伺服器地址
		8564,							//代理伺服器埠
		"proxyUID",						//代理賬號
		"proxyPwd",						//代理密碼
		"xxx.xxx.xxx.xxx",				//目標伺服器地址
		5876							//目標伺服器埠
		);

	//剩下的就是等待代理伺服器返回資料觸發pProxy->OnProxyRecv方法
	
	delete pProxy;
	delete pUsrInterface;

	return 0;
}

4.Flyweight模式

Flyweight.hpp:

#ifndef _FLY_WEIGHT_HPP
#define _FLY_WEIGHT_HPP

#include <string>
#include <vector>

typedef std::string xc;

class FlyWeight
{
public:
	FlyWeight(){}
	~FlyWeight(){};
	xc mKey;
};

class FlyWeightMgr
{
public:
	FlyWeightMgr(){};
	virtual ~FlyWeightMgr()
	{
		for( size_t i = 0; i < mFlyWeights.size(); ++i )
		{
			delete mFlyWeights[i];
		}
		mFlyWeights.clear();
	};

	FlyWeight* GetFlyWeight( const xc &key )
	{
		for( size_t i = 0; i < mFlyWeights.size(); ++i )
		{
			if( mFlyWeights[i]->mKey == key )
			{
				return mFlyWeights[i];
			}
		}
		FlyWeight *p = new FlyWeight;
		p->mKey = key;
		mFlyWeights.push_back( p );
		return p;
	}

private:

	std::vector< FlyWeight* > mFlyWeights;
};

#endif

Main.cpp:

#include "FlayWeight.hpp"

//作用:共享例項,已存在就返回,不存在就新建,然後追加到緩衝池中等待被使用
//這種模式,我們應該經常使用,只是不知道叫什麼名字而已
//一般這種模式,我們會對物件的建立和銷燬內部進行管理

int main()
{
	//典型管理器
	FlyWeightMgr *pMgr = new FlyWeightMgr;

	//獲取值為xfx的元件
	FlyWeight *p1 = pMgr->GetFlyWeight("xfx");
	FlyWeight *p2 = pMgr->GetFlyWeight("xfx");

	//這兩個值必然相等為true
	bool b = p1 == p2;

	delete pMgr;
	return 0;
}

5.Bridge模式

Bridge.hpp:

#ifndef _BRIDGE_HPP
#define _BRIDGE_HPP
//移動
class Move
{
public:
	Move(){}
	virtual ~Move(){}
	virtual void move() = 0;
};

//地面單位移動
class LandMove : public Move
{
public:
	LandMove(){}
	~LandMove(){}
	void move(){}
};

//空中單位移動
class AirMove : public Move
{
public:
	AirMove(){}
	~AirMove(){}
	void move(){}
};

class Unit
{
public:
	Unit( Move *p )
	{
		mp = p;
	}
	virtual ~Unit(){}
	virtual void move()
	{
		mp->move();
	}
	//...其他方法
protected:
	Move *mp;

	//...其他屬性
};


//scv 地面單位
class SCV : public Unit
{
public:
	SCV( Move *p )
		:Unit( p )
	{}
	~SCV(){}
};

//坦克 地面單位
class Tank : public Unit
{
public:
	Tank( Move *p )
		:Unit( p )
	{}
	virtual ~Tank(){}
};

//維京 空中單位
class Viking : public Unit
{
public:
	Viking( Move *p )
		:Unit( p )
	{}
	~Viking(){}
};

//渡鴉 空中單位
class Raven : public Unit
{
public:
	Raven( Move *p )
		:Unit( p )
	{}
	~Raven(){}
};

#endif

Main.cpp:

#include "Bridge.hpp"

//作用:將本來錄屬於物件的行為,單獨抽象出來成類,通過介面提供
//這樣做的好處是,可以降低耦合,當行為發生改變時,原來的物件我們根本不用去管
//例如星際爭霸2中的單位例子:

int main()
{
	//地面單位移動演算法,需要檢測碰撞什麼的
	Move *pLandMove = new LandMove;
	Unit *pScv = new SCV( pLandMove );
	Unit *pTank = new Tank( pLandMove );

	//空中單位移動演算法,基本不需要檢測地圖碰撞
	Move *pAirMove = new AirMove;
	Unit *pViking = new Viking( pAirMove );
	Unit *pRaven = new Raven( pAirMove );

	pScv->move();
	pTank->move();

	pViking->move();
	pRaven->move();

	delete pScv;
	delete pTank;
	delete pViking;
	delete pRaven;

	delete pLandMove;
	delete pAirMove;

	return 0;
}

6.Decorator模式


Decorator.hpp:

#ifndef _DECORATOR_HPP
#define _DECORATOR_HPP
#include <stdio.h>

class Component
{
public:
	Component(){}
	virtual ~Component(){}
	virtual void Operate(){}
};

//預設的職責,只有檔案壓縮
class File7z : public Component
{
public:
	File7z(){}
	~File7z(){}
	virtual void Operate()
	{
		printf( "7z檔案壓縮中...\n" );
	}
};

class Algorithm : public Component
{
public:
	Algorithm( Component *p )
	{
		mp = p;
	}
	virtual ~Algorithm()
	{
		delete mp;
	}
protected:
	//上一個操作物件
	Component *mp;
};



class AES256 : public Algorithm
{
public:
	AES256( Component *p )
		:Algorithm( p )
	{}
	~AES256(){}
	virtual void Operate()
	{
		//上一個職責
		mp->Operate();
		printf( "aes256加密中..\n" );
	}
};

class CheckError : public Algorithm
{
public:
	CheckError( Component *p )
		:Algorithm( p )
	{}
	~CheckError(){}
	virtual void Operate()
	{
		//上一個職責
		mp->Operate();
		printf( "檢測檔案包是否出錯中...\n" );
	}
};

#endif

Main.cpp:

#include "Decorator.hpp"

//作用:給一個物件的行為新增新的職責,兩兩直接可以相互組合成新的職責,而不用在定義新的組合功能類
//例如檔案壓縮過程 壓縮->加密->檢測 等等例子可能不是太恰當,記住這種新增職責的思想即可
int main()
{
    //預設只有檔案壓縮
    Component *pFile7z = new File7z;

    //給pFile7z新增加密
    Component *pAes256 = new AES256( pFile7z );

    //給pFile7z加密後檢測是否出錯
    Component *pCheck = new CheckError( pAes256 );

    //執行
    pCheck->Operate();
    delete pCheck;
    
    //或者直接鏈式操作
    printf( "----\n" );
    pCheck = new CheckError( new AES256( new File7z ) );
    pCheck->Operate();

    delete pCheck;
    return 0;
}


未完待續...