設計模式6:Adapter Pattern (適配器模式)

來源:互聯網
上載者:User

來自於:http://www.cnblogs.com/zhenyulu/articles/39386.html

參考於:http://www.dofactory.com/Patterns/PatternAdapter.aspx

一、 適配器(Adapter)模式

適配器模式把一個類的介面變換成用戶端所期待的另一種介面,從而使原本介面不匹配而無法在一起工作的兩個類能夠在一起工作。

名稱由來

這很像變壓器(Adapter),變壓器把一種電壓變換成另一種電壓。美國的生活用電電壓是110V,而中國的電壓是220V。如果要在中國使用美國電器,就必須有一個能把220V電壓轉換成110V電壓的變壓器。這個變壓器就是一個Adapter。

Adapter模式也很像貨物的封裝過程:被封裝的貨物的真實樣子被封裝所掩蓋和改變,因此有人把這種模式叫做封裝(Wrapper)模式。事實上,大家經常寫很多這樣的Wrapper類,把已有的一些類封裝起來,使之有能滿足需要的介面。

適配器模式的兩種形式

適配器模式有類的適配器模式和對象的適配器模式兩種。我們將分別討論這兩種Adapter模式。

二、 類的Adapter模式的結構:

 

由圖中可以看出,Adaptee類沒有Request方法,而客戶期待這個方法。為了使客戶能夠使用Adaptee類,提供一個中間環節,即類Adapter類,Adapter類實現了Target介面,並繼承自Adaptee,Adapter類的Request方法重新封裝了Adaptee的SpecificRequest方法,實現了適配的目的。

因為Adapter與Adaptee是繼承的關係,所以這決定了這個適配器模式是類的。

該適配器模式所涉及的角色包括:

目標(Target)角色:這是客戶所期待的介面。因為C#不支援多繼承,所以Target必須是介面,不可以是類。
源(Adaptee)角色:需要適配的類。
適配器(Adapter)角色:把源介面轉換成目標介面。這一角色必須是類。

三、 類的Adapter模式示意性實現:

下面的程式給出了一個類的Adapter模式的示意性的實現:

using System;<br />using System.Collections.Generic;<br />using System.Linq;<br />using System.Text;</p><p>namespace Adapter_Pattern<br />{<br /> // Class Adapter pattern -- Structural example<br /> using System;</p><p> // "ITarget"<br /> interface ITarget<br /> {<br /> // Methods<br /> void Request();<br /> }</p><p> // "Adaptee"<br /> class Adaptee<br /> {<br /> // Methods<br /> public void SpecificRequest()<br /> {<br /> Console.WriteLine("Called SpecificRequest()");<br /> }<br /> }</p><p> // "Adapter"<br /> class Adapter : Adaptee, ITarget<br /> {<br /> // Implements ITarget interface<br /> public void Request()<br /> {<br /> // Possibly do some data manipulation<br /> // and then call SpecificRequest<br /> this.SpecificRequest();<br /> }<br /> }</p><p> /**/<br /> /// <summary><br /> /// Client test<br /> /// </summary><br /> public class Client<br /> {<br /> public static void Main(string[] args)<br /> {<br /> // Create adapter and place a request<br /> ITarget t = new Adapter();<br /> t.Request();<br /> }<br /> }<br />}<br />

四、 對象的Adapter模式的結構:

 

可以看出:用戶端需要調用Request方法,而Adaptee沒有該方法,為了使用戶端能夠使用Adaptee類,需要提供一個封裝(Wrapper)類Adapter。這個封裝類封裝了一個Adaptee的執行個體,從而將用戶端與Adaptee銜接起來。由於Adapter與Adaptee是委派關係,這決定了這個適配器模式是對象的。

該適配器模式所涉及的角色包括:

目標(Target)角色:這是客戶所期待的介面。目標可以是具體的或抽象的類,也可以是介面。
源(Adaptee)角色:需要適配的類。
適配器(Adapter)角色:通過在內部封裝(Wrap)一個Adaptee對象,把源介面轉換成目標介面。

五、 對象的Adapter模式示意性實現:

下面的程式給出了一個類的Adapter模式的示意性的實現:

using System;<br />using System.Collections.Generic;<br />using System.Linq;<br />using System.Text;</p><p>namespace Adapter_Pattern<br />{<br /> // Adapter pattern -- Structural example </p><p> // "Target"<br /> class Target<br /> {<br /> // Methods<br /> virtual public void Request()<br /> {<br /> // Normal implementation goes here<br /> }<br /> }</p><p> // "Adapter"<br /> class Adapter : Target<br /> {<br /> // Fields<br /> private Adaptee adaptee = new Adaptee();</p><p> // Methods<br /> override public void Request()<br /> {<br /> // Possibly do some data manipulation<br /> // and then call SpecificRequest<br /> adaptee.SpecificRequest();<br /> }<br /> }</p><p> // "Adaptee"<br /> class Adaptee<br /> {<br /> // Methods<br /> public void SpecificRequest()<br /> {<br /> Console.WriteLine("Called SpecificRequest()");<br /> }<br /> }</p><p> /**/<br /> /// <summary><br /> /// Client test<br /> /// </summary><br /> public class Client<br /> {<br /> public static void Main(string[] args)<br /> {<br /> // Create adapter and place a request<br /> Target t = new Adapter();<br /> t.Request();<br /> Console.Read();<br /> }<br /> }<br />}<br />

六、 在什麼情況下使用適配器模式

在以下各種情況下使用適配器模式:

1、 系統需要使用現有的類,而此類的介面不符合系統的需要。
2、 想要建立一個可以重複使用的類,用於與一些彼此之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起工作。這些源類不一定有很複雜的介面。
3、 (對對象適配器而言)在設計裡,需要改變多個已有子類的介面,如果使用類的適配器模式,就要針對每一個子類做一個適配器,而這不太實際。

七、 一個實際應用Adapter模式的例子

下面的程式示範了Class Adapter與Object Adapter的應用。

using System;<br />using System.Collections.Generic;<br />using System.Linq;<br />using System.Text;</p><p>namespace Adapter_Pattern<br />{<br /> // Example of implementing the Adapter pattern<br /> using System;</p><p> // Target<br /> public interface ICar<br /> {<br /> void Drive();<br /> }</p><p> // Direct use without Adapter<br /> public class CToyota : ICar<br /> {<br /> public void Drive()<br /> {<br /> Console.WriteLine("Vroom Vroom, we're off in our Toyota");<br /> }<br /> }</p><p> // Adaptee<br /> public class CCessna<br /> {<br /> public void Fly()<br /> {<br /> Console.WriteLine("Static runup OK, we're off in our C172");<br /> }<br /> }</p><p> // Class Adapter<br /> public class CDrivableCessna : CCessna, ICar<br /> {<br /> public void Drive() { base.Fly(); }<br /> }</p><p> // Object Adapter<br /> public class CDrivableCessna2 : ICar<br /> {<br /> private CCessna m_oContained;</p><p> public CDrivableCessna2()<br /> {<br /> m_oContained = new CCessna();<br /> }</p><p> public void Drive() { m_oContained.Fly(); }<br /> }</p><p> // Client<br /> public class Client<br /> {<br /> public static void Main(string[] args)<br /> {<br /> ICar oCar = new CToyota();</p><p> Console.Write("Class Adapter: Driving an Automobile");<br /> oCar.Drive();<br /> oCar = new CDrivableCessna();<br /> Console.Write("Driving a Cessna");<br /> oCar.Drive();<br /> oCar = new CDrivableCessna2();<br /> Console.Write(" Object Adapter: Driving a Cessna");<br /> oCar.Drive();<br /> }<br /> }<br />}<br />
八、 關於Adapter模式的討論

Adapter模式在實現時有以下這些值得注意的地方:

1、 目標介面可以省略,模式發生退化。但這種做法看似平庸而並不平庸,它可以使Adaptee不必實現不需要的方法(可以參考Default Adapter模式)。其表現形式就是父類實現預設方法,而子類只需實現自己獨特的方法。這有些像模板(Template)模式。
2、 適配器類可以是抽象類別。
3、 帶參數的適配器模式。使用這種辦法,適配器類可以根據參數返還一個合適的執行個體給用戶端。

 

其他的例子

// Adapter pattern -- Real World example<br />using System;<br />namespace DoFactory.GangOfFour.Adapter.RealWorld<br />{</p><p> /// <summary></p><p> /// MainApp startup class for Real-World </p><p> /// Adapter Design Pattern.</p><p> /// </summary></p><p> class MainApp<br /> {</p><p> /// <summary></p><p> /// Entry point into console application.</p><p> /// </summary></p><p> static void Main()<br /> {</p><p> // Non-adapted chemical compound</p><p> Compound unknown = new Compound("Unknown");</p><p> unknown.Display();</p><p> // Adapted chemical compounds</p><p> Compound water = new RichCompound("Water");</p><p> water.Display();</p><p> Compound benzene = new RichCompound("Benzene");</p><p> benzene.Display();</p><p> Compound ethanol = new RichCompound("Ethanol");</p><p> ethanol.Display();</p><p> // Wait for user</p><p> Console.ReadKey();</p><p> }</p><p> }</p><p> /// <summary></p><p> /// The 'Target' class</p><p> /// </summary></p><p> class Compound<br /> {</p><p> protected string _chemical;</p><p> protected float _boilingPoint;</p><p> protected float _meltingPoint;</p><p> protected double _molecularWeight;</p><p> protected string _molecularFormula;</p><p> // Constructor</p><p> public Compound(string chemical)<br /> {</p><p> this._chemical = chemical;</p><p> }</p><p> public virtual void Display()<br /> {</p><p> Console.WriteLine("/nCompound: {0} ------ ", _chemical);</p><p> }</p><p> }</p><p> /// <summary></p><p> /// The 'Adapter' class</p><p> /// </summary></p><p> class RichCompound : Compound<br /> {</p><p> private ChemicalDatabank _bank;</p><p> // Constructor</p><p> public RichCompound(string name)</p><p> : base(name)<br /> {</p><p> }</p><p> public override void Display()<br /> {</p><p> // The Adaptee</p><p> _bank = new ChemicalDatabank();</p><p> _boilingPoint = _bank.GetCriticalPoint(_chemical, "B");</p><p> _meltingPoint = _bank.GetCriticalPoint(_chemical, "M");</p><p> _molecularWeight = _bank.GetMolecularWeight(_chemical);</p><p> _molecularFormula = _bank.GetMolecularStructure(_chemical);</p><p> base.Display();</p><p> Console.WriteLine(" Formula: {0}", _molecularFormula);</p><p> Console.WriteLine(" Weight : {0}", _molecularWeight);</p><p> Console.WriteLine(" Melting Pt: {0}", _meltingPoint);</p><p> Console.WriteLine(" Boiling Pt: {0}", _boilingPoint);</p><p> }</p><p> }</p><p> /// <summary></p><p> /// The 'Adaptee' class</p><p> /// </summary></p><p> class ChemicalDatabank<br /> {</p><p> // The databank 'legacy API'</p><p> public float GetCriticalPoint(string compound, string point)<br /> {</p><p> // Melting Point</p><p> if (point == "M")<br /> {</p><p> switch (compound.ToLower())<br /> {</p><p> case "water": return 0.0f;</p><p> case "benzene": return 5.5f;</p><p> case "ethanol": return -114.1f;</p><p> default: return 0f;</p><p> }</p><p> }</p><p> // Boiling Point</p><p> else<br /> {</p><p> switch (compound.ToLower())<br /> {</p><p> case "water": return 100.0f;</p><p> case "benzene": return 80.1f;</p><p> case "ethanol": return 78.3f;</p><p> default: return 0f;</p><p> }</p><p> }</p><p> }</p><p> public string GetMolecularStructure(string compound)<br /> {</p><p> switch (compound.ToLower())<br /> {</p><p> case "water": return "H20";</p><p> case "benzene": return "C6H6";</p><p> case "ethanol": return "C2H5OH";</p><p> default: return "";</p><p> }</p><p> }</p><p> public double GetMolecularWeight(string compound)<br /> {</p><p> switch (compound.ToLower())<br /> {</p><p> case "water": return 18.015;</p><p> case "benzene": return 78.1134;</p><p> case "ethanol": return 46.0688;</p><p> default: return 0d;</p><p> }</p><p> }</p><p> }</p><p>}</p><p>

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.