[設計模式之禪讀書筆記]003_設計模式六大原則(三):依賴倒置原則(Dependence Inversion Principle)


序言

   依賴倒置,這個概念看起來很玄乎,其實很簡單。這也是我看所有技術書的心態,在心態上戰勝這本書,那么它的內容,也就能很容易理解了。依賴倒置的英文定義如下:

   High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions。

   英文不給力的自動跳過吧。這個原則的意思就是,代碼要依賴於抽象,而不依賴於實現。這又是什么意思呢?我有個比喻:公司需要你嗎?需要,這叫依賴。但是你覺得你所在的公司離開你就不行了嗎?顯然不是的,公司只是依賴於具有擁有技能的人。所以,這里的擁有技能的人是你和你同事的抽象,當然也包括社會上的人。那所謂的倒置是什么呢?公司如果依賴你,那就叫正置;但是公司現在依賴的是具有技能的人,是抽象集合體,這就叫倒置。所謂正置是指依賴於具體的實現,而倒置則是依賴於對具體的抽象。

正文

   1. 依賴倒置有什么好處呢?

       依賴倒置原則的要求是依賴於抽象,那么這個問題就相當於在問,基於抽象編程有什么好處呢?這樣問題就容易回答了。抽象是什么?抽象是將一群具有相似特征和行為的個體歸為一類。這樣,我就不用為每一個個體實現的類定制函數了。試想,加入我有一個函數名叫“殺雞”,它的參數不是抽象的雞,而是土雞,那么當我要殺飼料雞的時候,還需要將“殺雞”重載一個參數為飼料雞的函數。這樣會十分麻煩。所以,依賴倒置的好處之一是:

不必為某一具體個體定制特別的處理函數,可以避免大量的無趣的函數重載。

       那還有其他好處嗎?當然有了,依賴倒置可以降低具體類之間的耦合性。這是什么意思呢?看下面一段不好的程序:

 1 class QiRuiQQ{
 2 public:
 3     void run(){
 4         cout<<"QiRuiQQ running..."<<endl;
 5     }
 6 };
 7 
 8 class Driver{
 9 public:
10     void drive(Benz bz){
11         bz.run();
12     }
13 };
14 
15 int main(){
16 
17     Driver *d = new Driver();
18     QiRuiQQ *q = new QiRuiQQ();
19     d->drive(*q);
20 
21     delete q;
22     delete d;
23 
24     return 0;
25 }

      這兩個類的耦合度如何呢?可以告訴你,太高了。為什么呢?試想,假如Driver要開法拉利怎么辦?我現在有一個法拉利的類:

1 class Ferrari{
2 public:
3     void run(){
4         cout<<"Ferrari running..."<<endl;
5     }
6 };

      那Driver只能眼睜睜的看着這樣一輛超級跑車,他卻開不走。如果要讓Driver能開法拉利,我們就需要為Drive加一個重載函數,而這函數體於QiRuiQQ的drive方法驚人的相似。那么我們怎么辦呢?這個時候就需要我們偉大的依賴倒置原則了,看符合依賴倒置的代碼吧:

 1 /**
 2  *車輛的抽象
 3  **/
 4 class ICar{
 5 public:
 6     virtual void run(){}
 7 };
 8 /**
 9  *司機的抽象
10  **/
11 class IDriver{
12 public:
13     virtual void drive(ICar car){}
14 };
15 /**
16  *車輛的具象:奇瑞QQ
17  **/
18 class QiRuiQQ:public ICar{
19 public:
20     void run(){
21         cout<<"QiRuiQQ running..."<<endl;
22     }
23 };
24 /**
25  *車輛的具象:法拉利
26  **/
27 class Ferrari:public ICar{
28 public:
29     void run(){
30         cout<<"Ferrari running..."<<endl;
31     }
32 };
33 /**
34  *司機的具象
35  **/
36 class Driver:public IDriver{
37 public:
38     void drive(ICar* car){
39         car->run();
40     }
41 };
42 
43 int main(){
44 
45     Driver *d = new Driver();
46     QiRuiQQ *q = new QiRuiQQ();
47     d->drive(q);
48 
49     delete q;
50     delete d;
51     system("pause");
52     return 0;
53 }

運行結果:

   QiRuiQQ running...
   請按任意鍵繼續. . .

 

   此時無論你給司機什么車,司機都會開了,只要那個車繼承了ICar。這樣就降低了兩個類別的耦合度了。所以,依賴倒置的第二個好處就出來了:

降低類間的耦合度。

   2. 依賴的實現方法有哪些?

       所謂的依賴實現,這個概念貌似很牛逼,其實很簡單的,就是怎么把參數傳給另一個類。作者給了三種方法,我們來看看到底是哪三種吧。

         ◇a. 構造函數(構造對象的時候傳入另一個對象)

         ◇b. setter方法(Java里有Bean的概念,C++也可以完全模仿啊!其實就是一個設置成員屬性的值的函數而已)

         ◇c. 接口聲明依賴對象(就是我們上面的代碼了)

總結

   1. 依賴倒置原則可以避免大量的函數重載。

   2. 依賴倒置原則可以降低類間的耦合度。

   3. 依賴的實現方法有三種,分別是:構造函數、setter方法、接口聲明依賴對象。

注意

   依賴倒置雖然給我們提供了方便之門,但是從上面的代碼也可以看出,它很容易類的規模膨脹,如果為每一個類都聲明一個接口,那就會膨脹的可怕。所以,對於我們這些技術人來說,在技術的應用上,要有拿捏,不能沒有,也不能全都是。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM