欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
橋接模式(Bridge Pattern)

一、 橋梁(Bridge)模式

橋梁模式是一個(gè)非常有用的模式,也是比較復雜的一個(gè)模式。熟悉這個(gè)模式對于理解面向對象的設計原則,包括"開(kāi)-閉"原則(OCP)以及組合/聚合復用原則(CARP)都很有幫助。理解好這兩個(gè)原則,有助于形成正確的設計思想和培養良好的設計風(fēng)格。

橋梁模式的用意

【GOF95】在提出橋梁模式的時(shí)候指出,橋梁模式的用意是"將抽象化(Abstraction)與實(shí)現化(Implementation)脫耦,使得二者可以獨立地變化"。這句話(huà)有三個(gè)關(guān)鍵詞,也就是抽象化、實(shí)現化和脫耦。

抽象化

存在于多個(gè)實(shí)體中的共同的概念性聯(lián)系,就是抽象化。作為一個(gè)過(guò)程,抽象化就是忽略一些信息,從而把不同的實(shí)體當做同樣的實(shí)體對待【LISKOV94】。

實(shí)現化

抽象化給出的具體實(shí)現,就是實(shí)現化。

脫耦

所謂耦合,就是兩個(gè)實(shí)體的行為的某種強關(guān)聯(lián)。而將它們的強關(guān)聯(lián)去掉,就是耦合的解脫,或稱(chēng)脫耦。在這里,脫耦是指將抽象化和實(shí)現化之間的耦合解脫開(kāi),或者說(shuō)是將它們之間的強關(guān)聯(lián)改換成弱關(guān)聯(lián)。

將兩個(gè)角色之間的繼承關(guān)系改為聚合關(guān)系,就是將它們之間的強關(guān)聯(lián)改換成為弱關(guān)聯(lián)。因此,橋梁模式中的所謂脫耦,就是指在一個(gè)軟件系統的抽象化和實(shí)現化之間使用組合/聚合關(guān)系而不是繼承關(guān)系,從而使兩者可以相對獨立地變化。這就是橋梁模式的用意。


二、 橋梁模式的結構

橋梁模式【GOF95】是對象的結構模式,又稱(chēng)為柄體(Handle and Body)模式或接口(Interface)模式。

下圖所示就是一個(gè)實(shí)現了橋梁模式的示意性系統的結構圖。

可以看出,這個(gè)系統含有兩個(gè)等級結構,也就是:

  • 由抽象化角色和修正抽象化角色組成的抽象化等級結構。
  • 由實(shí)現化角色和兩個(gè)具體實(shí)現化角色所組成的實(shí)現化等級結構。

橋梁模式所涉及的角色有:

  • 抽象化(Abstraction)角色:抽象化給出的定義,并保存一個(gè)對實(shí)現化對象的引用。
  • 修正抽象化(Refined Abstraction)角色:擴展抽象化角色,改變和修正父類(lèi)對抽象化的定義。
  • 實(shí)現化(Implementor)角色:這個(gè)角色給出實(shí)現化角色的接口,但不給出具體的實(shí)現。必須指出的是,這個(gè)接口不一定和抽象化角色的接口定義相同,實(shí)際上,這兩個(gè)接口可以非常不一樣。實(shí)現化角色應當只給出底層操作,而抽象化角色應當只給出基于底層操作的更高一層的操作。
  • 具體實(shí)現化(Concrete Implementor)角色:這個(gè)角色給出實(shí)現化角色接口的具體實(shí)現。


三、 橋梁模式的示意性源代碼

 

// Bridge pattern -- Structural example  
using System;

// "Abstraction"
class Abstraction
{
  
// Fields
  protected Implementor implementor;

  
// Properties
  public Implementor Implementor
  
{
    
set{ implementor = value; }
  }


  
// Methods
  virtual public void Operation()
  
{
    implementor.Operation();
  }

}


// "Implementor"
abstract class Implementor
{
  
// Methods
  abstract public void Operation();
}


// "RefinedAbstraction"
class RefinedAbstraction : Abstraction
{
  
// Methods
  override public void Operation()
  
{
    implementor.Operation();
  }

}


// "ConcreteImplementorA"
class ConcreteImplementorA : Implementor
{
  
// Methods
  override public void Operation()
  
{
    Console.WriteLine(
"ConcreteImplementorA Operation");
  }

}


// "ConcreteImplementorB"
class ConcreteImplementorB : Implementor
{
  
// Methods
  override public void Operation()
  
{
    Console.WriteLine(
"ConcreteImplementorB Operation");
  }

}


/// 
/// Client test
/// 

public class Client
{
  
public static void Main( string[] args )
  
{
    Abstraction abstraction 
= new RefinedAbstraction();

    
// Set implementation and call
    abstraction.Implementor = new ConcreteImplementorA();
    abstraction.Operation();

    
// Change implemention and call
    abstraction.Implementor = new ConcreteImplementorB();
    abstraction.Operation();
  }

}

 


四、 調制解調器問(wèn)題

感覺(jué)《敏捷軟件開(kāi)發(fā)-原則、模式與實(shí)踐》中關(guān)于Bridge模式的例子很好。(《Java與模式》一書(shū)33章的對變化的封裝一節也寫(xiě)得很不錯,推薦大家讀一讀。它深入的闡述了《Design Patterns Explained》一書(shū)中"1)Design to interfaces.2)Favor composition over inheritance. 3)Find what varies andencapsulate it"的三個(gè)觀(guān)點(diǎn)。)。

如圖所示,有大量的調制解調器客戶(hù)程序在使用Modem接口。Modem接口被幾個(gè)派生類(lèi)HayesModem、USRoboticsModem和EarniesModem實(shí)現。它很好地遵循了OCP、LSP和DIP。當增加新種類(lèi)的調制解調器時(shí),調制解調器的客戶(hù)程序不會(huì )受影響。

假定這種情形持續了幾年,并有許多調制解調器的客戶(hù)程序都在使用著(zhù)Modem接口?,F出現了一種不撥號的調制解調器,被稱(chēng)為專(zhuān)用調制解調器。它們位于一條專(zhuān)用連接的兩端。有幾個(gè)新應用程序使用這些專(zhuān)用調制解調器,它們無(wú)需撥號。我們稱(chēng)這些使用者為DedUser。但是,客戶(hù)希望當前所有的調制解調器客戶(hù)程序都可以使用這些專(zhuān)用調制解調器。他們不希望去更改許許多多的調制解調器客戶(hù)應用程序,所以完全可以讓這些調制解調器客戶(hù)程序去撥一些假(dummy)電話(huà)號碼。

如果能選擇的話(huà),我們會(huì )把系統的設計更改為下圖所示的那樣。

我們把撥號和通信功能分離為兩個(gè)不同的接口。原來(lái)的調制解調器實(shí)現這兩個(gè)接口,而調制解調器客戶(hù)程序使用這兩個(gè)接口。DedUser只使用Modem接口,而DedicateModem只實(shí)現Modem接口。但這樣做會(huì )要求我們更改所有的調制解調器客戶(hù)程序--這是客戶(hù)不允許的。

一個(gè)可能的解決方案是讓DedicatedModem從Modem派生并且把dial方法和hangup方法實(shí)現為空,就像下面這樣:

幾個(gè)月后,已經(jīng)有了大量的DedUser,此時(shí)客戶(hù)提出了一個(gè)新的更改。為了能撥?chē)H電話(huà)號碼、信用卡電話(huà)、PIN標識電話(huà)等等,必修對現有dial中使用char[10]存儲號碼改為能夠撥打任意長(cháng)度的電話(huà)號碼。

顯然,所有的調制解調器客戶(hù)程序都必須更改??蛻?hù)同意了對調制解調器客戶(hù)程序的更改,因為他們別無(wú)選擇。糟糕的是,現在必須要去告訴DedUser的編寫(xiě)者,他們必須要更改他們的代碼!你可以想象他們聽(tīng)到這個(gè)會(huì )有多高興。本來(lái)他們是不用調用dial的。

這就是許多項目都會(huì )具有的那種有害的混亂依賴(lài)關(guān)系。系統某一部分中的一個(gè)雜湊體(kludge)創(chuàng )建了一個(gè)有害的依賴(lài)關(guān)系,最終導致系統中完全無(wú)關(guān)的部分出現問(wèn)題。

如果使用ADAPTER模式解決最初的問(wèn)題的話(huà),就可以避免這個(gè)嚴重問(wèn)題。如圖:

請注意,雜湊體仍然存在。適配器仍然要模擬連接狀態(tài)。然而,所有的依賴(lài)關(guān)系都是從適配器發(fā)起的。雜湊體和系統隔離,藏身于幾乎無(wú)人知曉的適配器中。

BRIDGE模式

看待這個(gè)問(wèn)題,還有另外一個(gè)方式?,F在,出現了另外一種切分Modem層次結構的方式。如下圖:

這不是一個(gè)理想的結構。每當增加一款新硬件時(shí),就必須創(chuàng )建兩個(gè)新類(lèi)--一個(gè)針對專(zhuān)用的情況,一個(gè)針對撥號的情況。每當增加一種新連接類(lèi)型時(shí),就必須創(chuàng )建3個(gè)新類(lèi),分別對應3款不同的硬件。如果這兩個(gè)自由度根本就是不穩定的,那么不用多久,就會(huì )出現大量的派生類(lèi)。

在類(lèi)型層次結構具有多個(gè)自由度的情況中,BRIDGE模式通常是有用的。我們可以把這些層次結構分開(kāi)并通過(guò)橋把它們結合到一起,而不是把它們合并起來(lái)。如圖:

我們把調制解調器類(lèi)層次結構分成兩個(gè)層次結構。一個(gè)表示連接方法,另一個(gè)表示硬件。

這個(gè)結構雖然復雜,但是很有趣。它的創(chuàng )建不會(huì )影響到調制解調器的使用者,并且還完全分離了連接策略和硬件實(shí)現。ModemConnectController的每個(gè)派生類(lèi)代表了一個(gè)新的連接策略。在這個(gè)策略的實(shí)現中可以使用sendlmp、receivelmp、diallmp和hanglmp。新imp方法的增加不會(huì )影響到使用者??梢允褂肐SP來(lái)給連接控制類(lèi)增加新的接口。這種做法可以創(chuàng )建出一條遷移路徑,調制解調器的客戶(hù)程序可以沿著(zhù)這條路徑慢慢地得到一個(gè)比dial和hangup層次更高的API。


五、 另外一個(gè)實(shí)際應用Bridge模式的例子

該例子演示了業(yè)務(wù)對象(BusinessObject)通過(guò)Bridge模式與數據對象(DataObject)解耦。數據對象的實(shí)現可以在不改變客戶(hù)端代碼的情況下動(dòng)態(tài)進(jìn)行更換。

 

// Bridge pattern -- Real World example
using System;
using System.Collections;

// "Abstraction"
class BusinessObject
{
  
// Fields
  private DataObject dataObject;
  
protected string group;

  
// Constructors
  public BusinessObject( string group )
  
{
    
this.group = group;
  }


  
// Properties
  public DataObject DataObject
  
{
    
set{ dataObject = value; }
    
getreturn dataObject; }
  }


  
// Methods
  virtual public void Next()
  
{ dataObject.NextRecord(); }

  
virtual public void Prior()
  
{ dataObject.PriorRecord(); }

  
virtual public void New( string name )
  
{ dataObject.NewRecord( name ); }

  
virtual public void Delete( string name )
  
{ dataObject.DeleteRecord( name ); }

  
virtual public void Show()
  
{ dataObject.ShowRecord(); }

  
virtual public void ShowAll()
  
{
    Console.WriteLine( 
"Customer Group: {0}", group );
    dataObject.ShowAllRecords();
  }

}


// "RefinedAbstraction"
class CustomersBusinessObject : BusinessObject
{
  
// Constructors
  public CustomersBusinessObject( string group )
    : 
base( group ){}

  
// Methods
  override public void ShowAll()
  
{
    
// Add separator lines
    Console.WriteLine();
    Console.WriteLine( 
"------------------------" );
    
base.ShowAll();
    Console.WriteLine( 
"------------------------" );
  }

}


// "Implementor"
abstract class DataObject
{
  
// Methods
  abstract public void NextRecord();
  
abstract public void PriorRecord();
  
abstract public void NewRecord( string name );
  
abstract public void DeleteRecord( string name );
  
abstract public void ShowRecord();
  
abstract public void ShowAllRecords();
}


// "ConcreteImplementor"
class CustomersDataObject : DataObject
{
  
// Fields
  private ArrayList customers = new ArrayList();
  
private int current = 0;

  
// Constructors
  public CustomersDataObject()
  
{
    
// Loaded from a database
    customers.Add( "Jim Jones" );
    customers.Add( 
"Samual Jackson" );
    customers.Add( 
"Allen Good" );
    customers.Add( 
"Ann Stills" );
    customers.Add( 
"Lisa Giolani" );
  }


  
// Methods
  public override void NextRecord()
  
{
    
if( current <= customers.Count - 1 )
      current
++;
  }


  
public override void PriorRecord()
  
{
    
if( current > 0 )
      current
--;
  }


  
public override void NewRecord( string name )
  
{
    customers.Add( name );
  }


  
public override void DeleteRecord( string name )
  
{
    customers.Remove( name );
  }


  
public override void ShowRecord()
  
{
    Console.WriteLine( customers[ current ] );
  }


  
public override void ShowAllRecords()
  
{
    
foreachstring name in customers )
      Console.WriteLine( 
" " + name );
  }

}


/// 
/// Client test
/// 

public class BusinessApp
{
  
public static void Main( string[] args )
  
{
    
// Create RefinedAbstraction
    CustomersBusinessObject customers =
      
new CustomersBusinessObject(" Chicago ");

    
// Set ConcreteImplementor
    customers.DataObject = new CustomersDataObject();

    
// Exercise the bridge
    customers.Show();
    customers.Next();
    customers.Show();
    customers.Next();
    customers.Show();
    customers.New( 
"Henry Velasquez" );

    customers.ShowAll();
  }

}

 

 

六、 在什么情況下應當使用橋梁模式

根據上面的分析,在以下的情況下應當使用橋梁模式:

  • 如果一個(gè)系統需要在構件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個(gè)層次之間建立靜態(tài)的聯(lián)系。
  • 設計要求實(shí)現化角色的任何改變不應當影響客戶(hù)端,或者說(shuō)實(shí)現化角色的改變對客戶(hù)端是完全透明的。
  • 一個(gè)構件有多于一個(gè)的抽象化角色和實(shí)現化角色,系統需要它們之間進(jìn)行動(dòng)態(tài)耦合。
  • 雖然在系統中使用繼承是沒(méi)有問(wèn)題的,但是由于抽象化角色和具體化角色需要獨立變化,設計要求需要獨立管理這兩者。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
C#設計模式(8)——橋接模式(Bridge Pattern)
Java描述設計模式(08):橋接模式
設計模式(六)橋連模式Bridge(結構型)
設計模式-結構型-橋接模式
C#設計模式系列:橋接模式(Bridge)
Bridge模式,Decorator模式
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久