乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      橋接模式(Bridge Pattern)

       漂在北方的狼 2007-03-28

      一、 橋梁(Bridge)模式

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

      橋梁模式的用意

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

      抽象化

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

      實現(xiàn)化

      抽象化給出的具體實現(xiàn),就是實現(xiàn)化。

      脫耦

      所謂耦合,就是兩個實體的行為的某種強關聯(lián)。而將它們的強關聯(lián)去掉,就是耦合的解脫,或稱脫耦。在這里,脫耦是指將抽象化和實現(xiàn)化之間的耦合解脫開,或者說是將它們之間的強關聯(lián)改換成弱關聯(lián)。

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


      二、 橋梁模式的結構

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

      下圖所示就是一個實現(xiàn)了橋梁模式的示意性系統(tǒng)的結構圖。

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

      • 由抽象化角色和修正抽象化角色組成的抽象化等級結構。
      • 由實現(xiàn)化角色和兩個具體實現(xiàn)化角色所組成的實現(xiàn)化等級結構。

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

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


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

       

      // 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();
        }

      }

       


      四、 調制解調器問題

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

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

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

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

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

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

      幾個月后,已經(jīng)有了大量的DedUser,此時客戶提出了一個新的更改。為了能撥國際電話號碼、信用卡電話、PIN標識電話等等,必修對現(xiàn)有dial中使用char[10]存儲號碼改為能夠撥打任意長度的電話號碼。

      顯然,所有的調制解調器客戶程序都必須更改??蛻敉饬藢φ{制解調器客戶程序的更改,因為他們別無選擇。糟糕的是,現(xiàn)在必須要去告訴DedUser的編寫者,他們必須要更改他們的代碼!你可以想象他們聽到這個會有多高興。本來他們是不用調用dial的。

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

      如果使用ADAPTER模式解決最初的問題的話,就可以避免這個嚴重問題。如圖:

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

      BRIDGE模式

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

      http://www./upfiles/images/picbox/Pic96.gif

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

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

      http://www./upfiles/images/picbox/Pic97.gif

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

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


      五、 另外一個實際應用Bridge模式的例子

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

       

      // 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();
        }

      }

       

       

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

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

      • 如果一個系統(tǒng)需要在構件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個層次之間建立靜態(tài)的聯(lián)系。
      • 設計要求實現(xiàn)化角色的任何改變不應當影響客戶端,或者說實現(xiàn)化角色的改變對客戶端是完全透明的。
      • 一個構件有多于一個的抽象化角色和實現(xiàn)化角色,系統(tǒng)需要它們之間進行動態(tài)耦合。
      • 雖然在系統(tǒng)中使用繼承是沒有問題的,但是由于抽象化角色和具體化角色需要獨立變化,設計要求需要獨立管理這兩者。

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多