設計模式:橋接模式優勢比較

原文連接:http://blog.csdn.net/jason0539/article/details/22568865html

生活中的一個例子:
    拿汽車在路上行駛的來講。既有小汽車又有公共汽車,它們都不但能在市區中的公路上行駛,也能在高速公路上行駛。這你會發現,對於交通工具(汽車)有不一樣的類型,它們所行駛的環境(路)也有不一樣類型,在軟件系統中就要適應兩個方面(不一樣車型,不一樣道路)的變化,怎樣實現才能應對這種變化呢?

概述:
在軟件系統中,某些類型因爲自身的邏輯,它具備兩個或多個維度的變化,那麼如何應對這種「多維度的變化」?如何利用面嚮對象的技術來使得該類型可以輕鬆的沿着多個方向進行變化,而又不引入額外的複雜度?這就要使用Bridge模式。
意圖:
   將抽象部分與實現部分分離,使它們均可以獨立的變化。
                                                                    ——《設計模式》GOF 
java

上面這些話我也沒看懂。。太抽象了,可是一看代碼你就明白是怎麼回事了。
結構圖:
設計模式

傳統的作法:
        經過類繼承的方式來作上面的例子;

先看一下類結構圖:ide

代碼實現:工具

[java]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1.         //基類 路  
  2. class Road {  
  3.     void run() {  
  4.         System.out.println("路");  
  5.     }  
  6. }  
  7.   
  8. //市區街道  
  9. class Street extends Road {  
  10.     void run() {  
  11.         System.out.println("市區街道");  
  12.     }  
  13. }  
  14.   
  15. //高速公路  
  16. class SpeedWay extends Road {  
  17.     void run() {  
  18.         System.out.println("高速公路");  
  19.     }  
  20. }  
  21. //小汽車在市區街道行駛  
  22. class CarOnStreet extends Street {  
  23.     void run() {  
  24.         System.out.println("小汽車在市區街道行駛");  
  25.     }  
  26. }  
  27. //小汽車在高速公路行駛  
  28. class CarOnSpeedWay extends SpeedWay {  
  29.     void run() {  
  30.         System.out.println("小汽車在高速公路行駛");  
  31.     }  
  32. }  
  33. //公交車在市區街道行駛  
  34. class BusOnStreet extends Street {  
  35.     void run() {  
  36.         System.out.println("公交車在市區街道行駛");  
  37.     }  
  38. }  
  39. //公交車在高速公路行駛  
  40. class BusOnSpeedWay extends SpeedWay {  
  41.     void run() {  
  42.         System.out.println("公交車在高速公路行駛");  
  43.     }  
  44. }  
  45. //測試  
  46. public static void main(String[] args) {  
  47.       
  48.     //小汽車在高速公路行駛  
  49.     CarOnSpeedWay carOnSpeedWay = new CarOnSpeedWay();  
  50.     carOnSpeedWay.run();  
  51.     //公交車在市區街道行駛  
  52.     BusOnStreet busOnStreet = new BusOnStreet();  
  53.     busOnStreet.run();  
  54.   
  55. }  

缺點:
     可是咱們說這樣的設計是脆弱的,仔細分析就能夠發現,它仍是存在不少問題,首先它在遵循開放-封閉原則的同時,違背了類的單一職責原則,即一個類只有一個引發它變化的緣由,而這裏引發變化的緣由卻有兩個,即路類型的變化和汽車類型的變化;其次是重複代碼會不少,不一樣的汽車在不一樣的路上行駛也會有一部分的代碼是相同的;
測試

再次是類的結構過於複雜,繼承關係太多,難於維護,最後最致命的一點是擴展性太差。若是變化沿着汽車的類型和不一樣的道路兩個方向變化,咱們會看到這個類的結構會迅速的變龐大。
spa

應用設計模式
       橋接模式(Bridge)來作;

先看一下類結構圖:.net

代碼實現:設計

[java]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. abstract class AbstractRoad{  
  2.     AbstractCar aCar;  
  3.     void run(){};  
  4. }  
  5. abstract class AbstractCar{  
  6.     void run(){};  
  7. }  
  8.   
  9. class Street extends AbstractRoad{  
  10.     @Override  
  11.     void run() {  
  12.         // TODO Auto-generated method stub  
  13.         super.run();  
  14.         aCar.run();  
  15.         System.out.println("在市區街道行駛");  
  16.     }  
  17. }  
  18. class SpeedWay extends AbstractRoad{  
  19.     @Override  
  20.     void run() {  
  21.         // TODO Auto-generated method stub  
  22.         super.run();  
  23.         aCar.run();  
  24.         System.out.println("在高速公路行駛");  
  25.     }  
  26. }  
  27. class Car extends AbstractCar{  
  28.     @Override  
  29.     void run() {  
  30.         // TODO Auto-generated method stub  
  31.         super.run();  
  32.         System.out.print("小汽車");  
  33.     }  
  34. }  
  35. class Bus extends AbstractCar{  
  36.     @Override  
  37.     void run() {  
  38.         // TODO Auto-generated method stub  
  39.         super.run();  
  40.         System.out.print("公交車");  
  41.     }  
  42. }  
  43.   
  44. public static void main(String[] args){  
  45.       
  46.     AbstractRoad speedWay = new SpeedWay();  
  47.     speedWay.aCar = new Car();  
  48.     speedWay.run();  
  49.       
  50.     AbstractRoad street = new Street();  
  51.     street.aCar = new Bus();  
  52.     street.run();  
  53. }  

 能夠看到,經過對象組合的方式,Bridge 模式把兩個角色之間的繼承關係改成了耦合的關係,從而使這二者能夠從容自若的各自獨立的變化,這也是Bridge模式的本意。
      這樣增長了客戶程序與路與汽車的耦合。其實這樣的擔憂是沒有必要的,由於這種耦合性是因爲對象的建立所帶來的,徹底能夠用建立型模式去解決。在應用時結合建立型設計模式來處理具體的問題。
應用設計模式:
       橋接模式(Bridge)來作(
多維度變化);
       結合上面的例子,增長一個維度"人",不一樣的人開着不一樣的汽車在不一樣的路上行駛(三個維度);
       結合上面增長一個類"人",並從新調用.
代碼實現:code

[java]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. abstract class People {  
  2.     AbstractRoad road;  
  3.   
  4.     void run() {}  
  5. }  
  6.   
  7. class Man extends People{  
  8.     @Override  
  9.     void run() {  
  10.         // TODO Auto-generated method stub  
  11.         super.run();  
  12.         System.out.print("男人開着");  
  13.         road.run();  
  14.     }  
  15. }  
  16. class Woman extends People{  
  17.     @Override  
  18.     void run() {  
  19.         // TODO Auto-generated method stub  
  20.         super.run();  
  21.         System.out.print("女人開着");  
  22.         road.run();  
  23.     }  
  24. }  
  25.   
  26. public static void main(String[] args) {  
  27.   
  28.     AbstractRoad speedWay = new SpeedWay();  
  29.     speedWay.aCar = new Car();  
  30.       
  31.     People man = new Man();  
  32.     man.road = speedWay;  
  33.     man.run();  
  34. }  


效果及實現要點:
1.Bridge模式使用「對象間的組合關係」解耦了抽象和實現之間固有的綁定關係,使得抽象和實現能夠沿着各自的維度來變化。
2.所謂抽象和實現沿着各自維度的變化,即「子類化」它們,獲得各個子類以後,即可以任意它們,從而得到不一樣路上的不一樣汽車。
3.Bridge模式有時候相似於多繼承方案,可是多繼承方案每每違背了類的單一職責原則(即一個類只有一個變化的緣由),複用性比較差。Bridge模式是比多繼承方案更好的解決方法。
4.Bridge模式的應用通常在「兩個很是強的變化維度」,有時候即便有兩個變化的維度,可是某個方向的變化維度並不劇烈——換言之兩個變化不會致使縱橫交錯的結果,並不必定要使用Bridge模式。

適用性:
   在如下的狀況下應當使用橋樑模式:
1.若是一個系統須要在構件的抽象化角色和具體化角色之間增長更多的靈活性,避免在兩個層次之間創建靜態的聯繫。 
2.設計要求實現化角色的任何改變不該當影響客戶端,或者說實現化角色的改變對客戶端是徹底透明的。
3.一個構件有多於一個的抽象化角色和實現化角色,系統須要它們之間進行動態耦合。 
4.雖然在系統中使用繼承是沒有問題的,可是因爲抽象化角色和具體化角色須要獨立變化,設計要求須要獨立管理這二者。


總結:
      Bridge模式是一個很是有用的模式,也很是複雜,它很好的符合了開放-封閉原則和優先使用對象,而不是繼承這兩個面向對象原則。




小龍評論


經過橋接模式是否使用的比較,優勢很明顯。這樣,能夠更加容易地理解橋接模式的內涵。

另外,該博主寫的設計模式專欄http://blog.csdn.net/column/details/jason0539-shejimoshi.html,的確都很不錯,力薦!

相關文章
相關標籤/搜索