C++設計模式系列之二結構型模式
阿新 • • 發佈:2019-02-17
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;
}
未完待續...