1. 程式人生 > >bridge模式和stradegy模式的區別

bridge模式和stradegy模式的區別

下邊三段分別來自CSDN論壇的貼子和一篇blogjava的文章,看了之後令我茅塞頓開,為表尊重不在冗述,直接貼原文了。

實際上所有模式可以只分為類模式和物件模式兩種,類模式是用繼承而物件模式是用委託  
Bridge模式和Strategy模式相似就是因為他們都將任務委託給了另外一個介面的具體實現,  
他們之間的區別在於Bridge的目的是讓底層實現和上層介面可以分別演化,從而提高移植性  
而Strategy的目的是將複雜的演算法封裝起來,從而便於替換不同的演算法。  
因此可以想象一般情況下Bridge的實現幾乎不會在執行時更改而Strategy的演算法則很有可能  
需要在執行時更換,這就導致在細節方面需要考慮的因素可能會很不相同。

strategy模式是為了擴充套件和修改,並提供動態配置。它往往可以在同一環境當中使用不同的策略,就是呼叫不同的派生類。其內部實現是自由的,不受已有的類介面的限制(很多時候根本就不呼叫現成的介面)。  
bridge模式是往往是為了利用已有的方法或類。它將原來不統一,不相容的介面封裝起來,變成統一的介面。它的應用往往是不同的環境或平臺下只能選擇一 種,比如說在windows平臺下只能用WinClass,而在unix平臺下只能用UnixClass.它的主要作用不是配置而是定義通用介面。  
據個例子來說:我要畫園,要實心園,我可以用SolidPen來配置,畫虛線園可以用dashedPen來配置。這是strategy模式。  
而同樣是畫園,我是在windows下來畫實心園,就用windowPen+solidPen來配置,在unix下畫實心園就用 unixPen+solidPen來配置。如果要再windows下畫虛線園,就用windowsPen+dashedPen來配置,要在unix下畫虛 線園,就用unixPen+dashedPen來配置。  
我這裡僅僅是就一種情況來說strategy和bridge的組合應用,其他的組合可能性隨環境變化而多種多樣。從中可以看出,bridge和strategy是可能組合使用,側重不同方面的。  
模式某種角度上來講就是物件組合。不要看他們都是物件組合就好像是一樣的。模式的動機,意圖,使用場合,組合方式,這些都是模式的一部分。其中細微的不同足以區分不同的模式。

橋接(Bridge)模式是結構型模式的一種,而策略(strategy)模式則屬於行為模式。以下是它們的UML結構圖。

在橋接模式中,Abstraction通過聚合的方式引用Implementor。

從橋接模式與策略模式談起 - 一半是火焰,一半是海水 - BlogJava - silence - 守望者

在策略模式中,Context也使用聚合的方式引用Startegy抽象介面。

從橋接模式與策略模式談起 - 一半是火焰,一半是海水 - BlogJava - silence - 守望者

從他們的結構圖可知,在這兩種模式中,都存在一個物件使用聚合的方式引用另一個物件的抽象介面的情況,而且該抽象介面的實現可以有多種並且可以替換。可以說兩者在表象上都是呼叫者與被呼叫者之間的解耦,以及抽象介面與實現的分離。

那麼兩者的區別體現在什麼地方呢?

1. 首先,在形式上,兩者還是有一定區別的,對比兩幅結構圖,我們可以發現,在橋接模式中不僅Implementor具有變化 (ConcreateImplementior),而且Abstraction也可以發生變化(RefinedAbstraction),而且兩者的變化 是完全獨立的,RefinedAbstraction與ConcreateImplementior之間鬆散耦合,它們僅僅通過Abstraction與 Implementor之間的關係聯絡起來。而在策略模式中,並不考慮Context的變化,只有演算法的可替代性。

2. 其次在語意上,橋接模式強調Implementor介面僅提供基本操作,而Abstraction則基於這些基本操作定義更高層次的操作。而策略模式強調 Strategy抽象介面的提供的是一種演算法,一般是無狀態、無資料的,而Context則簡單呼叫這些演算法完成其操作。

3. 橋接模式中不僅定義Implementor的介面而且定義Abstraction的介面,Abstraction的介面不僅僅是為了與 Implementor通訊而存在的,這也反映了結構型模式的特點:通過繼承、聚合的方式組合類和物件以形成更大的結構。在策略模式中,Startegy 和Context的介面都是兩者之間的協作介面,並不涉及到其它的功能介面,所以它是行為模式的一種。行為模式的主要特點就是處理的是物件之間的通訊方 式,往往是通過引入中介者物件將通訊雙方解耦,在這裡實際上就是將Context與實際的演算法提供者解耦。

所以相對策略模式,橋接模式要表達的內容要更多,結構也更加複雜。橋接模式表達的主要意義其實是介面隔離的原則,即把本質上並不內聚的兩種體系區別 開來,使得它們可以鬆散的組合,而策略在解耦上還僅僅是某一個演算法的層次,沒有到體系這一層次。從結構圖中可以看到,策略的結構是包容在橋接結構中的,橋 接中必然存在著策略模式,Abstraction與Implementor之間就可以認為是策略模式,但是橋接模式一般Implementor將提供一系 列的成體系的操作,而且Implementor是具有狀態和資料的靜態結構。而且橋接模式Abstraction也可以獨立變化。

Bridge  例子: Bridge遵循的是介面隔離原則的典型。如 JDBC, 我們都知道JDBC是使用Bridge模式進行設計的,DriverManager就是其中的Abstraction,java.sql.Driver是Implementor,com.mysql.jdbc.Driver是Implementor的一個具體實現(請參考GOF的Bridge模式的描述)。大家注意了,前一個Driver是一個介面,後者卻是一個類,它實現了前面的Driver介面。

還有 現在流行的DAO 介面規範

其他例子:

  1. abstract class  Shape{   
  2. public void  draw();   
  3. }   
  4. //這裡業務出現了多種畫圖方式,DP1,DP2……
  5. //抽象出接口出DP1,DP2
  6. interface  Drawing{   
  7. public void  drawLine();   
  8. public void  drawCircle();   
  9. }   
  10. class  V1Drawing{   
  11. public void  drawLine(){};   
  12. public void  drawCircle(){};   
  13. }   
  14. class  V2Drawing{   
  15. public void  drawLine(){};   
  16. public void  drawCircle(){};   
  17. }   
  18. //使用組合 ,聚集Drawing
  19. class  Rectangle  extends  Shape{   
  20. public void  draw(Drawing dp){   
  21.         dp.drawLine();   
  22.     }   
  23. }   
  24. class  Circle  extends  Shape{   
  25. public void  draw(Drawing dp){   
  26.         dp.drawCircle();   
  27.     }   
  28. }
  29. //抽象類Shape的派生類,使用一組實現(DP1,DP2)的介面
  30. //使得派生類不依賴於一組具體的實現,從設計模式而言,這稱為Bridge模式

Stategy 例子:

首先,我們建立一個抽象類RepTempRule 定義一些公用變數和方法:

public abstract class RepTempRule{

protected String oldString="";
public void setOldString(String oldString){
this.oldString=oldString;
}

protected String newString="";
public String getNewString(){
return newString;
}



public abstract void replace() throws Exception;


}

在RepTempRule中 有一個抽象方法abstract需要繼承明確,這個replace裡其實是替代的具體方法.
我們現在有兩個字元替代方案,
1.將文字中aaa替代成bbb;
2.將文字中aaa替代成ccc;

對應的類分別是RepTempRuleOne RepTempRuleTwo

public class RepTempRuleOne extends RepTempRule{


public void replace() throws Exception{

//replaceFirst是jdk1.4新特性
newString=oldString.replaceFirst("aaa", "bbbb")
System.out.println("this is replace one");

}


}

public class RepTempRuleTwo extends RepTempRule{


public void replace() throws Exception{

newString=oldString.replaceFirst("aaa", "ccc")
System.out.println("this is replace Two");

}


}

第二步:我們要建立一個演算法解決類,用來提供客戶端可以自由選擇演算法。

public class RepTempRuleSolve {

  private RepTempRule strategy;

  public RepTempRuleSolve(RepTempRule rule){
this.strategy=rule;
}

  public String getNewContext(Site site,String oldString) {
return strategy.replace(site,oldString);
}

  public void changeAlgorithm(RepTempRule newAlgorithm) {
strategy = newAlgorithm;
}

}

呼叫如下:

public class test{

......

  public void testReplace(){

  //使用第一套替代方案
RepTempRuleSolve solver=new RepTempRuleSolve(new RepTempRuleSimple());
solver.getNewContext(site,context);

  //使用第二套

  solver=new RepTempRuleSolve(new RepTempRuleTwo());
solver.getNewContext(site,context);

  }

.....

}

我們達到了在執行期間,可以自由切換演算法的目的。

實際整個Strategy的核心部分就是抽象類的使用,使用Strategy模式可以在使用者需要變化時,修改量很少,而且快速.

Strategy和Factory有一定的類似,Strategy相對簡單容易理解,並且可以在執行時刻自由切換。Factory重點是用來建立物件。

Strategy適合下列場合:

1.以不同的格式儲存檔案;

2.以不同的演算法壓縮檔案;

3.以不同的演算法截獲圖象;

4.以不同的格式輸出同樣資料的圖形,比如曲線 或框圖bar等