3. 觀察者模式(也叫做觀察者-監聽者模式,發布-訂閱模式)
主要關注對象的一對多關系,也就是多個對象都依賴于一個對象,當該對象狀態改變時,其余對象都能得到對應的通知
如:一組數據(數據對象)->曲線圖,柱狀圖,圓餅圖
主題有更改,應該及時通知相應觀察者去處理相應的事件
class Observer
{
public:
?? ?//處理消息接口
?? ?virtual void handle(int msgid) = 0;
};
class Observer1
{
public:
?? ?//處理消息接口
?? ?void handle(int msgid)
?? ?{
?? ??? ?switch(msgid)
?? ??? ?{
?? ??? ?case 1:
?? ??? ??? ?cout<<"get 1"<<endl;
?? ??? ??? ?break;
?? ??? ?case 2:
?? ??? ??? ?cout<<"get 2"<<endl;
?? ??? ??? ?break;
?? ??? ?default:
?? ??? ??? ?cout<<"get error"<<endl;
?? ??? ??? ?break;
?? ??? ?}
?? ?}
};
class Observer2
{
public:
?? ?//處理消息接口
?? ?void handle(int msgid)
?? ?{
?? ??? ?switch(msgid)
?? ??? ?{
?? ??? ?case 2:
?? ??? ??? ?cout<<"get 2"<<endl;
?? ??? ??? ?break;
?? ??? ?default:
?? ??? ??? ?cout<<"get error"<<endl;
?? ??? ??? ?break;
?? ??? ?}
?? ?}
};
class Subject
{
public:?? ?
?? ?//添加對應觀察者
?? ?void addObserver(Observer* obser,int msgid)
?? ?{
?? ??? ?_subMap[msgid].push_back(obser);
?? ?}
?? ?//通知觀察者
?? ?void dispatch(int msg)
?? ?{
?? ??? ?auto it = _subMap.find(msgid);
?? ??? ?if(it != _subMap.end())
?? ??? ?{
?? ??? ??? ?for(Observer *pObser:it->second)
?? ??? ??? ?{
?? ??? ??? ??? ?pObser->handle(msgid):
?? ??? ??? ?}
?? ??? ?}
?? ?}
private:
?? ?//前面的int代表消息id,后面表示對其感興趣的觀察者列表
?? ?unordered_map<int,list<Observer*>> _subMap;
};
觀察者模式實際上就是創建一個主題類,然后當有消息來到的時候,主題負責通知各個觀察者,也就是函數調用
4.代理Proxy模式:通過代理類來控制實際對象的訪問權限
客戶 ?助理Proxy ?老板:委托類
//下面為一個案例,將視頻分為Vip和免費,不同身份可以獲取的視頻不同
class VideoSite
{
?? ?virtual void freeMovie() = 0;//免費電影
?? ?virtual void vipMovie() = 0;//vip電影
};
//這個是我們的網站,實現看vip電影和free電影,也就是我們的委托類
class FixBugVideoSite: public Video Site
{
public:
?? ?virtual void freeMovie()
?? ?{
?? ??? ?cout<<"see free"<<endl;
?? ?}
?? ?virtual void vipMovie()
?? ?{
?? ??? ?cout<<"see vip"<<endl;
?? ?}
};
//下面就是我們免費電影的代理
class FreeVideoSiteProxy : public VideoSite
{
public:
?? ?FreeVideoSiteProxy()
?? ?{
?? ??? ?pVideo = new FixBugVideoSite();
?? ?}
?? ?~ FreeVideoSiteProxy()
?? ?{
?? ??? ?delete pVideo;
?? ?}
?? ?
?? ?virtual void freeMovie()?
?? ?{
?? ??? ?pVideo->freeMovie();//通過代理對象的freeMovie,來訪問真正委托類對象的freeMovie
?? ?}
?? ?virtual void vipMovie()?
?? ?{
?? ??? ?cout<<"你沒充錢,不讓你訪問";
?? ?}
private:
?? ?VideoSite *pVideo;
};
實際上上述代理模式的原理在于創建一個代理類,在代理類中定義委托類指針,不同的代理類指行不同的函數
基類指針指向代理類對象,都使用基類指針保證安全
5.適配器模式
讓不兼容的接口可以一起工作
示例
電腦 -> 投影 ->投影儀?
VGA HDMI Typec 有這三種接口
如果VGA的電腦,投影儀也是VGA,那么就不需要轉換
class VGA
{
public:
?? ?virtual void play() = 0;
?? ?string getType() const{return "VGA";}
};
//這個就是支持VGA接口的投影儀
class TV01 : public VGA
{
public:
?? ?void play()
?? ?{
?? ??? ?cout<<"VGA接口"<<endl;
?? ?}
};
//這個就是支持VGA接口的電腦
class Computer : public VGA
{
public:
?? ?void playVedio(VGA *pVGA)
?? ?{
?? ??? ?pVGA->play();
?? ?}
};
//這時候有一批新的投影儀,只支持HDMI接口
class HDMI
{
public:
?? ?virtual void play() = 0;
};
class TV02 : public HDMI
{
public:
?? ?void play()
?? ?{
?? ??? ?cout<<"HDMI接口"<<endl;
?? ?}
};
此時你使用電腦連接新的投影儀,無法連接
換一個電腦:代碼重構
但是實際上很難去重構
方法2:買一個轉換頭,轉換信號:也就是適配器類
class VGAtoHDMI : public VGA
{
public:
?? ?VGAtoHDMI(HDMI *p):phdmi(p){};
?? ?void play()//該方法相當于轉換頭,做信號轉換的
?? ?{
?? ??? ?phdmi->play():
?? ?}
private:
?? ?HDMI *phdmi;
};
這個適配器模式實際上就是重寫了老接口的函數,轉為新接口的函數,就是更換組件
6.裝飾器模式
和代理模式非常接近,主要是增加現有類的功能
?