第六章(隔離)

都在說解耦合,但是如何解,哪些情況下有偶爾呢?看看前人的總結總是好的

此處都是針對編譯時的解偶爾,不涉及鏈接和最後發佈。

1、編譯時耦合

1.1 IsA的關係

繼承:class D: public B

不管繼承方式,B的變化都將影響D的重新編譯。D的重新編譯將會繼續遞歸下去

1.2 Has A/holds A

D中包含b1,b2對象。b1,b2的變化會影響D的編譯

1.3 內聯函數

D內聯函數的實現變化,都會影響包含接口的重新編譯。內聯函數儘量不要有函數調用,這樣其實是有依賴關係下去的。

1.4私有成員/保護成員

與1.2有點類似,private變量的類型,增加,刪除都會影響該類。函數參數,返回值也會影響其重新編譯

1.5 包含指令

明確的include。不用include的頭文件被包含,也會導致相應文件重新編譯

1.6 默認參數

默認參數變化

1.7 枚舉類型變化

宏定義,typedef,const全局值,枚舉都會導致重新編譯

所以所有錯誤碼或則類型定義在一個頭文件中,對於大型項目不是什麼好方法


2、隔離技術。如何隔離,針對相應情況相應的處理,而不是完完全全按照下面方法,因爲這些方法也有弊端

2.1 移除私有繼承

因爲是私有繼承,目的一般是希望使用裏面的部分方法作爲輔助。

解決方案:通過代理模式即可,將繼承的基類申明成成員類。然後子類提供部分訪問函數,另外此處不要使用內聯,否則就還是進入了耦合。失去了代理,前置申明解耦的意義了。另外寫代碼時候發現一個私有繼承比較有意思的寫法

基類

class CInsulateHelp
{
public:
 CInsulateHelp();
 ~CInsulateHelp();

 void f(int);
protected:
 void f_protected(int);
private:
 
};

子類私有繼承

class CInsulate: private CInsulateHelp
{
public:
 CInsulate();
 ~CInsulate();
 
 void Test();

 // 該語句註釋掉,f就是protected了,是無法被外部訪問的了。
 // 因爲是private繼承。函數也是成員對象!!!,也可以當變量使用
 CInsulateHelp::f;

 // 也可以把protected的成員申明成public.但是無法改變private類型,因爲private子類自己都訪問不到。
 CInsulateHelp::f_protected;
private:
};

解耦的重寫方法就是在CInsulate申明一個CInsulateHelp的指針即可。當然指針在內部就需要注意operator=,拷貝,析構指針的用法了。可以使用scoped_ptr,shared_ptr來明確所有權

2.2 消除嵌入式數據成員

與2.1改寫方式類似,使用代理模式即可,將成員變量有對象改寫爲指針

2.3 消除私有成員函數

因爲私有成員函數變量也會導致類變化,如果私有成員函數的功能是輔助函數,我們完全可以通過其它方式解耦合。

通過提供靜態函數或則全局函數,當然實現是在cpp中,如果需要使用類中的變量,第一個參數用this指針即可解決。

static void fHelp(CInsulateHelp* pHelp, int)
 {

 }

2.4 移除保護成員函數

如果基類提供一些保護成員函數,目的是給子類使用,方便子類在實現virtual時調用。這樣實際會污染基類,讓基類去關心子類,提供幫助給子類了

class Base

{

public:

virtual void draw() = 0;

protected:

void drawLine(); // 方便子類畫圓

}

改進方案

提供一個專門的輔助類,需要使用包含它,不需要的不用它,減少了基類的負擔和耦合,如果需要基類成員變量,提供一個this指針即可

class Scribe

{

pulbic;
void drawLine();

}

2.5 同樣是2.4的問題,另外的一種解決方法

如果2.4中單獨提取一個輔助類不合適,比如2.4中需要使用this指針去改變成員的值,即子類需要訪問的不僅僅是輔助函數,而是實際需要設置基類成員的函數,需要與基類緊密相連的,拆離到單獨的類中會將類的職責搞混亂。不太合適分離

我們可以爲Base提供一個供客戶使用的純虛接口類,只提供draw

再提供一個BaseImpl繼承自Base,提供一些真正要設置成員的函數,真正的實現再繼承自BaseImpl。這樣BaseImpl的變化,不會影響客戶的編譯,而子類又使用了各個輔助函數,或則設置函數。


2.6 移除編譯器生成的函數

2.7 移除包含指令

2.8 刪除默認參數

2.9 刪除枚舉類型

      1.私有枚舉類型可以放到cpp中

       2.枚舉常量可以通過static const int代替,然後提供static的訪問函數,這樣值變化,不會導致其它文件重新編譯。但是可能會影響性能,因爲多一個間接訪問函數

       3.枚舉用作返回值,參數類型,儘量定義在類的內部,不要試圖去重用它們,不用把它們和其它類似的放在一塊。如該文件的錯誤碼就放在該文件中,不用把所有錯誤碼放在一個文件中


3. 整體的隔離技術

3.1 協議類。即抽象接口類,是一個近乎完美的隔離器

不包含任何成員變量,不繼承任何類

有一個virtual的析構函數

其它成員,全都是純虛的


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章