【GeekBand】C++面向?qū)ο蟾呒壘幊?第九周筆記

動機

由于某些類型的固有的實現(xiàn)邏輯,使得它們具有兩個變化的維度腕让,乃至多個維度的變化
那么該如何應(yīng)對這種多維度的變化孤钦?如何利用面向?qū)ο蠹夹g(shù)使得類型可以輕松沿著兩個乃至多個方向變化?而不引入額外的復(fù)雜度纯丸。

橋模式定義

將抽象部分(業(yè)務(wù)功能)與實現(xiàn)部分(平臺實現(xiàn))分離偏形,使得它們都可以獨立地變化。
讓我們直接上代碼觉鼻,分析一下沒有使用橋模式下的代碼如何難以獨立變化俊扭。

class Messager{
public:
    virtual void Login(string username, string password)=0;
    virtual void SendMessage(string message)=0;
    virtual void SendPicture(Image image)=0;

    virtual void PlaySound()=0;
    virtual void DrawShape()=0;
    virtual void WriteText()=0;
    virtual void Connect()=0;
    
    virtual ~Messager(){}
};


//平臺實現(xiàn)

class PCMessagerBase : public Messager{
public:
    
    virtual void PlaySound(){
        //**********
    }
    virtual void DrawShape(){
        //**********
    }
    virtual void WriteText(){
        //**********
    }
    virtual void Connect(){
        //**********
    }
};

class MobileMessagerBase : public Messager{
public:
    
    virtual void PlaySound(){
        //==========
    }
    virtual void DrawShape(){
        //==========
    }
    virtual void WriteText(){
        //==========
    }
    virtual void Connect(){
        //==========
    }
};



//業(yè)務(wù)抽象

class PCMessagerLite : public PCMessagerBase {
public:
    
    virtual void Login(string username, string password){
        
        PCMessagerBase::Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        PCMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        PCMessagerBase::DrawShape();
        //........
    }
};



class PCMessagerPerfect : public PCMessagerBase {
public:
    
    virtual void Login(string username, string password){
        
        PCMessagerBase::PlaySound();
        //********
        PCMessagerBase::Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        PCMessagerBase::PlaySound();
        //********
        PCMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        PCMessagerBase::PlaySound();
        //********
        PCMessagerBase::DrawShape();
        //........
    }
};


class MobileMessagerLite : public MobileMessagerBase {
public:
    
    virtual void Login(string username, string password){
        
        MobileMessagerBase::Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        MobileMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        MobileMessagerBase::DrawShape();
        //........
    }
};


class MobileMessagerPerfect : public MobileMessagerBase {
public:
    
    virtual void Login(string username, string password){
        
        MobileMessagerBase::PlaySound();
        //********
        MobileMessagerBase::Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        MobileMessagerBase::PlaySound();
        //********
        MobileMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        MobileMessagerBase::PlaySound();
        //********
        MobileMessagerBase::DrawShape();
        //........
    }
};


void Process(){
        //編譯時裝配
        Messager *m =
            new MobileMessagerPerfect();
}
類圖.JPG

通過閱讀上述代碼,可以發(fā)現(xiàn)一個問題坠陈,平臺的變化和版本的是兩個維度的問題萨惑,如果平臺增加捐康,那么增加的平臺下又增加多幾個版本,就是不同的平臺下面還分有若干版本庸蔼,子類數(shù)量會增多吹由。類的數(shù)量為1+n+nm*。
課程中提到橋模式朱嘴,讓我們一起來看看橋模式。
分析上述代碼粗合,
PCMessagerLite 和 MobilMessagerLite內(nèi)的函數(shù)基本相同萍嬉,不同的是平臺不同,Prefect版本也類似隙疚。那么可以嘗試將其進行合并和簡化壤追。

class Messager{
public:
    virtual void Login(string username, string password)=0;
    virtual void SendMessage(string message)=0;
    virtual void SendPicture(Image image)=0;

    virtual void PlaySound()=0;
    virtual void DrawShape()=0;
    virtual void WriteText()=0;
    virtual void Connect()=0;
    
    virtual ~Messager(){}
};

這個類中的存在兩個變化,需要將其進行拆分供屉。

class Messager{
public:
    virtual void Login(string username, string password)=0;
    virtual void SendMessage(string message)=0;
    virtual void SendPicture(Image image)=0;
    virtual ~Messager(){}
};
class MessagerImg{
public:
    virtual void PlaySound()=0;
    virtual void DrawShape()=0;
    virtual void WriteText()=0;
    virtual void Connect()=0;
    virtual ~MessagerImg(){}
};

這樣子行冰,就可以分別修改這兩個維度的代碼了。
拆分后伶丐,平臺只和MessagerImg有關(guān)悼做,從而修改平臺相關(guān)的代碼


class PCMessagerImg : public MessagerImg{
public:
    
    virtual void PlaySound(){
        //**********
    }
    virtual void DrawShape(){
        //**********
    }
    virtual void WriteText(){
        //**********
    }
    virtual void Connect(){
        //**********
    }
};
class MobileMessagerImg : public MessagerImg{
public:
    
    virtual void PlaySound(){
        //==========
    }
    virtual void DrawShape(){
        //==========
    }
    virtual void WriteText(){
        //==========
    }
    virtual void Connect(){
        //==========
    }
};

由于平臺類有一個接口,那么利用多態(tài)性哗魂,則可以對平臺相關(guān)的業(yè)務(wù)抽象進行簡化肛走。

class PCMessagerLite {
   MessagerImg *mImg;
public:
    
    virtual void Login(string username, string password){
        
       mImg->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        mImg->PCMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        mImg->DrawShape();
        //........
    }
};

經(jīng)過這么修改,可以發(fā)現(xiàn)版本和平臺不是繼承的關(guān)系录别,如果Mobile的代碼也如此修改朽色,那么可以發(fā)現(xiàn)其內(nèi)部成員函數(shù)是一樣的,則可以刪除其中一個组题,Lite版本可以合并為:

class MessagerLite:public Messager {
   MessagerImg *mImg;
public:
    virtual void Login(string username, string password){
        
       mImg->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        mImg->PCMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        mImg->DrawShape();
        //........
    }
};

類似地Perfect版本可以改為:

class MessagerPerfect:public Messager {
   MessagerImg *mImg;
public:
    virtual void Login(string username, string password){
        
       mImg->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        mImg->PCMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        mImg->DrawShape();
        //........
    }
};

根據(jù)重構(gòu)一書葫男,如果兩個子類有同樣的成員變量,可以將其提升到基類中崔列,并且添加對象的構(gòu)造函數(shù)來接受不同平臺的對象梢褐,則Messager類改為

class Messager{
protected:
       MessagerImg *mImg;
public:
    Messager(MessagerImg *_mImg):mImg(_mImg) {}
    virtual void Login(string username, string password)=0;
    virtual void SendMessage(string message)=0;
    virtual void SendPicture(Image image)=0;
    virtual ~Messager(){}
};

同樣,其子類也要有對象的構(gòu)造函數(shù)來初始化父類中的mImg赵讯。
最后代碼改為:

class Messager{
protected:
    MessagerImp *mImp;
public:
    Messager(MessagerImp *_mImp) :mImp(_mImp) { }
    virtual void Login(string username, string password) = 0;
    virtual void SendMessage(string _message) = 0;
    virtual void SendPicture(Image image) = 0;
    virtual ~Messager(){}
};
class MessagerImp{
public:
    virtual void PlaySound() = 0;
    virtual void DrawShape() = 0;
    virtual void WriteText() = 0;
    virtual void Connect() = 0;
    virtual ~MessagerImp() {}
};

//平臺實現(xiàn)

class PCMessagerImp : public MessagerImp{
public:

    virtual void PlaySound(){
        //**********
    }
    virtual void DrawShape(){
        //**********
    }
    virtual void WriteText(){
        //**********
    }
    virtual void Connect(){
        //**********
    }
};
class MobileMessagerImp : public MessagerImp{
public:

    virtual void PlaySound(){
        //**********
    }
    virtual void DrawShape(){
        //**********
    }
    virtual void WriteText(){
        //**********
    }
    virtual void Connect(){
        //**********
    }
};

//業(yè)務(wù)抽象

class MessagerLite :public Messager {
public:
    MessagerPerfect(MessagerImp *_messagerImp) :Messager(_messagerImp) { }
    virtual void Login(string username, string password){

        messageImp->Connect();
        //........
    }
    virtual void SendMessage(string _message){

        messageImp->WriteText();
        //........
    }
    virtual void SendPicture(Image image){

        messageImp->DrawShape();
        //........
    }
};



class MessagerPerfect :public Messager{
public:
    MessagerPerfect(MessagerImp *_messagerImp) :Messager(_messagerImp){ }
    virtual void Login(string username, string password){

        messagerImp->PlaySound();
        //********
        messagerImp->Connect();
        //........
    }
    virtual void SendMessage(string _message){

        messagerImp->PlaySound();
        //********
        messagerImp->WriteText();
        //........
    }
    virtual void SendPicture(Image image){

        messagerImp->PlaySound();
        //********
        messagerImp->DrawShape();
        //........
    }
};

void Process(){
    //運行時裝配
    MessagerImp *messagerImp = new PCMessagerImg();
    Messager *m = new MessagerPerfect(messagerImp);
}

所以總結(jié)一下:
橋模式使用對象間的組合關(guān)系解耦了抽象和實現(xiàn)之間固有的綁定關(guān)系利职,使得抽象和實現(xiàn)可以沿著各自的維度來變化。所謂抽象和實現(xiàn)沿著各自維度的變化瘦癌,即子類化它們猪贪。
一樣應(yīng)用在兩個非常強的變化維度,有時一個類也有多于兩個的變化維度讯私,這時可以使用Bridge的擴展模式(加指針)
具體步驟是:
1.分離該類中的不同維度的成員热押;
2.抽象維度的實現(xiàn)維度指針指向?qū)崿F(xiàn)維度西傀,從而產(chǎn)生聯(lián)系。這個指針便是“橋”桶癣。
3.針對實現(xiàn)進行修改拥褂。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市牙寞,隨后出現(xiàn)的幾起案子饺鹃,更是在濱河造成了極大的恐慌,老刑警劉巖间雀,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悔详,死亡現(xiàn)場離奇詭異,居然都是意外死亡惹挟,警方通過查閱死者的電腦和手機茄螃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來连锯,“玉大人住拭,你說我怎么就攤上這事激捏。” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵室叉,是天一觀的道長许师。 經(jīng)常有香客問我揪胃,道長艾君,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任吗购,我火速辦了婚禮医男,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捻勉。我一直安慰自己镀梭,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布踱启。 她就那樣靜靜地躺著报账,像睡著了一般。 火紅的嫁衣襯著肌膚如雪埠偿。 梳的紋絲不亂的頭發(fā)上透罢,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天,我揣著相機與錄音冠蒋,去河邊找鬼羽圃。 笑死,一個胖子當(dāng)著我的面吹牛抖剿,可吹牛的內(nèi)容都是我干的朽寞。 我是一名探鬼主播识窿,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼脑融!你這毒婦竟也來了喻频?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤肘迎,失蹤者是張志新(化名)和其女友劉穎甥温,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妓布,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡姻蚓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了秋茫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡乃秀,死狀恐怖肛著,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情跺讯,我是刑警寧澤枢贿,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站刀脏,受9級特大地震影響局荚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜愈污,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一耀态、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧暂雹,春花似錦首装、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至涧尿,卻和暖如春系奉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背姑廉。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工缺亮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人桥言。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓瞬内,卻偏偏與公主長得像迷雪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子虫蝶,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,107評論 2 356

推薦閱讀更多精彩內(nèi)容