.Net結(jié)構(gòu)型設(shè)計(jì)模式之適配器模式(Adapter)
一、動(dòng)機(jī)(Motivation)
在軟件系統(tǒng)中,由于應(yīng)用環(huán)境的變化,常常需要將“一些現(xiàn)存的對(duì)象”放在新的環(huán)境中應(yīng)用,但是新環(huán)境要求的接口是這些現(xiàn)存對(duì)象所不滿足的。
如何應(yīng)對(duì)這種“遷移的變化”?如何既能利用現(xiàn)有對(duì)象的良好實(shí)現(xiàn),同時(shí)又能滿足新的應(yīng)用環(huán)境所要求的接口?
二、意圖(Intent)
將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另一個(gè)接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
例說Adapter應(yīng)用
這種實(shí)際上是一種委派的調(diào)用,本來是發(fā)送請(qǐng)求給MyStack,但是MyStack實(shí)際上是委派給list去處理。MyStack在這里其實(shí)就是Adapter(適配對(duì)象),list即是Adaptee(被適配的對(duì)象),而IStack就是客戶期望的接口。太直接了,沒什么可說的。
三、結(jié)構(gòu)(Structure)
適配器有兩種結(jié)構(gòu)
1、對(duì)象適配器(更常用)
對(duì)象適配器使用的是對(duì)象組合的方案,它的Adapter和Adaptee的關(guān)系是組合關(guān)系,即上面例子中MyStack和list是組合關(guān)系。
OO中優(yōu)先使用組合模式,組合模式不適用再考慮繼承。因?yàn)榻M合模式更加松耦合,而繼承是緊耦合的,父類的任何改動(dòng)都要導(dǎo)致子類的改動(dòng)。
上面的例子就是對(duì)象適配器。
2、類適配器(不推薦使用)
下面的例子是類適配器。
Adapter繼承了ArrayList,也繼承了IStack接口,它既可以使用ArrayList里的方法,也可以使用IStack接口里的方法,這樣就感覺有點(diǎn)不倫不類。這個(gè)類違反了類應(yīng)該具有單一職責(zé)的原則,它既有ArrayList的職責(zé),也有IStack的職責(zé),因此這種類適配不是很常用,也不推薦使用。
注意:如果一個(gè)方法有可能要委托到2個(gè)或2個(gè)以上的對(duì)象,或者2個(gè)或2個(gè)以上的類需要委托,對(duì)于對(duì)象適配器,只需要增加幾個(gè)內(nèi)部的屬性就可以實(shí)現(xiàn)適配。
而對(duì)于類適配器,因?yàn)镃#中類只能是單一繼承,它不能繼承自2個(gè)或2個(gè)以上的類,所以類適配器這里便無法使用。
四、模式的組成
可以看出,在適配器模式的結(jié)構(gòu)圖有以下角色:
(1)、目標(biāo)角色(Target):定義Client使用的與特定領(lǐng)域相關(guān)的接口。
(2)、客戶角色(Client):與符合Target接口的對(duì)象協(xié)同。
(3)、被適配角色(Adaptee):定義一個(gè)已經(jīng)存在并已經(jīng)使用的接口,這個(gè)接口需要適配。
(4)、適配器角色(Adapte) :適配器模式的核心。它將對(duì)被適配Adaptee角色已有的接口轉(zhuǎn)換為目標(biāo)角色Target匹配的接口。對(duì)Adaptee的接口與Target接口進(jìn)行適配。
五、 適配器模式的具體實(shí)現(xiàn)
實(shí)現(xiàn)一個(gè)對(duì)棧的操作,有一個(gè)IStact接口,里面有三個(gè)方法Push(進(jìn)棧)、Pop(出棧)和GetTopItem(取最頂層元素),這個(gè)IStact接口將相當(dāng)于上面的Target,想要實(shí)現(xiàn)進(jìn)棧出棧的操作,如果自己去實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)顯得比較麻煩,在此可以將net提供的ArrayList類拿來一用,ArrayList類就是被適配的對(duì)象,相當(dāng)于上面的Adaptee。在寫一個(gè)適配類StactAdapter類完成功能就可以了。
/// <summary> /// 棧的接口 /// </summary> public interface IStack { void Push(object item); void Pop(); Object GetTopItem(); } /// <summary> /// 對(duì)象適配器 /// </summary> public class StactAdapter : IStack { ArrayList list; /// <summary> /// 構(gòu)造函數(shù)中實(shí)例化ArrayList /// </summary> public StactAdapter() { list = new ArrayList(); } /// <summary> /// 進(jìn)棧 /// </summary> /// <param name="item">壓入棧的元素</param> public void Push(object item) { list.Add(item); } /// <summary> /// 出棧 /// </summary> public void Pop() { list.RemoveAt(list.Count - 1); } /// <summary> /// 取最頂層的元素 /// </summary> /// <returns></returns> public Object GetTopItem() { return list[list.Count - 1]; } } /// <summary> /// 客戶調(diào)用 /// </summary> public class App { static void Main(string[] args) { IStack myStack = new StactAdapter(); myStack.Push("oec2003"); myStack.Push("oec2004"); myStack.Push("oec2005"); myStack.Pop(); Console.WriteLine(myStack.GetTopItem()); } }
六、適配器模式的實(shí)現(xiàn)要點(diǎn):
1、Adapter模式主要應(yīng)用于“希望復(fù)用一些現(xiàn)存的類,但是接口又與復(fù)用環(huán)境要求不一致的情況”,在遺留代碼復(fù)用、類庫遷移等方面非常有用。
2、GoF23定義了兩種Adapter模式的實(shí)現(xiàn)結(jié)構(gòu):對(duì)象適配器和類適配器。類適配器采用“多繼承”的實(shí)現(xiàn)方式,在C#語言中,如果被適配角色是類,Target的實(shí)現(xiàn)只能是接口,因?yàn)镃#語言只支持接口的多繼承的特性。在C#語言中類適配器也很難支持適配多個(gè)對(duì)象的情況,同時(shí)也會(huì)帶來了不良的高耦合和違反類的職責(zé)單一的原則,所以一般不推薦使用。對(duì)象適配器采用“對(duì)象組合”的方式,更符合松耦合精神,對(duì)適配的對(duì)象也沒限制,可以一個(gè),也可以多個(gè),但是,使得重定義Adaptee的行為較困難,這就需要生成Adaptee的子類并且使得Adapter引用這個(gè)子類而不是引用Adaptee本身。Adapter模式可以實(shí)現(xiàn)的非常靈活,不必拘泥于GoF23中定義的兩種結(jié)構(gòu)。例如,完全可以將Adapter模式中的“現(xiàn)存對(duì)象”作為新的接口方法參數(shù),來達(dá)到適配的目的。
3、Adapter模式本身要求我們盡可能地使用“面向接口的編程”風(fēng)格,這樣才能在后期很方便地適配。
適配器模式用來解決現(xiàn)有對(duì)象與客戶端期待接口不一致的問題,下面詳細(xì)總結(jié)下適配器兩種形式的優(yōu)缺點(diǎn)。
1、類的適配器模式:
優(yōu)點(diǎn):
(1)、可以在不修改原有代碼的基礎(chǔ)上來復(fù)用現(xiàn)有類,很好地符合 “開閉原則”
(2)、可以重新定義Adaptee(被適配的類)的部分行為,因?yàn)樵陬愡m配器模式中,Adapter是Adaptee的子類
(3)、僅僅引入一個(gè)對(duì)象,并不需要額外的字段來引用Adaptee實(shí)例(這個(gè)即是優(yōu)點(diǎn)也是缺點(diǎn))。
缺點(diǎn):
(1)、用一個(gè)具體的Adapter類對(duì)Adaptee和Target進(jìn)行匹配,當(dāng)如果想要匹配一個(gè)類以及所有它的子類時(shí),類的適配器模式就不能勝任了。因?yàn)轭惖倪m配器模式中沒有引入Adaptee的實(shí)例,光調(diào)用this.SpecificRequest方法并不能去調(diào)用它對(duì)應(yīng)子類的SpecificRequest方法。
(2)、采用了 “多繼承”的實(shí)現(xiàn)方式,帶來了不良的高耦合。
2、對(duì)象的適配器模式
優(yōu)點(diǎn):
(1)、可以在不修改原有代碼的基礎(chǔ)上來復(fù)用現(xiàn)有類,很好地符合 “開閉原則”(這點(diǎn)是兩種實(shí)現(xiàn)方式都具有的)
(2)、采用 “對(duì)象組合”的方式,更符合松耦合。
缺點(diǎn):
使得重定義Adaptee的行為較困難,這就需要生成Adaptee的子類并且使得Adapter引用這個(gè)子類而不是引用Adaptee本身。
3、適配器模式使用的場(chǎng)景:
(1)、系統(tǒng)需要復(fù)用現(xiàn)有類,而該類的接口不符合系統(tǒng)的需求
(2)、想要建立一個(gè)可重復(fù)使用的類,用于與一些彼此之間沒有太大關(guān)聯(lián)的一些類,包括一些可能在將來引進(jìn)的類一起工作。
(3)、對(duì)于對(duì)象適配器模式,在設(shè)計(jì)里需要改變多個(gè)已有子類的接口,如果使用類的適配器模式,就要針對(duì)每一個(gè)子類做一個(gè)適配器,而這不太實(shí)際。
七、.NET 中適配器模式的實(shí)現(xiàn)
說道適配器模式在Net中的實(shí)現(xiàn)就很多了,比如:System.IO里面的很多類都有適配器的影子,當(dāng)我們操作文件的時(shí)候,其實(shí)里面調(diào)用了COM的接口實(shí)現(xiàn)。以下兩點(diǎn)也是適配器使用的案例:
1.在.NET中復(fù)用COM對(duì)象:
COM對(duì)象不符合.NET對(duì)象的接口,使用tlbimp.exe來創(chuàng)建一個(gè)Runtime Callable Wrapper(RCW)以使其符合.NET對(duì)象的接口,COM Interop就好像是COM和.NET之間的一座橋梁。
2..NET數(shù)據(jù)訪問類(Adapter變體):
各種數(shù)據(jù)庫并沒有提供DataSet接口,使用DbDataAdapter可以將任何個(gè)數(shù)據(jù)庫訪問/存取適配到一個(gè)DataSet對(duì)象上,DbDataAdapter在數(shù)據(jù)庫和DataSet之間做了很好的適配。當(dāng)然還有SqlDataAdapter類型了,針對(duì)微軟SqlServer類型的數(shù)據(jù)庫在和DataSet之間進(jìn)行適配。
到此這篇關(guān)于.Net結(jié)構(gòu)型設(shè)計(jì)模式之適配器模式(Adapter)的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
ASP.Net?Core?MVC基礎(chǔ)系列之項(xiàng)目創(chuàng)建
這篇文章介紹了創(chuàng)建ASP.Net?Core?MVC項(xiàng)目的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-02-02ASP.NET中HttpContext對(duì)象下的屬性介紹
這篇文章介紹了ASP.NET中HttpContext對(duì)象下的屬性,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05ASP.NET?Core中的通用主機(jī)HostBuilder
這篇文章介紹了ASP.NET?Core中的通用主機(jī)HostBuilder,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04.Net創(chuàng)建型設(shè)計(jì)模式之原型模式(Prototype)
這篇文章介紹了.Net設(shè)計(jì)模式之原型模式(Prototype),文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05ASP.NET中Application、Cookie、Session、Cache和ViewState
本文主要介紹Application、Cookie、Session、Cache和ViewState,并總結(jié)了在什么情況下使用他們,希望對(duì)大家有所幫助。2016-04-04ASP.NET與數(shù)據(jù)庫相關(guān)技巧
[紅色]ASP.NET與數(shù)據(jù)庫相關(guān)技巧...2006-10-10詳解.net循環(huán)、邏輯語句塊(基礎(chǔ)知識(shí))
本篇是介紹.NET 基礎(chǔ)部分,主要簡(jiǎn)述循環(huán),判斷,對(duì)初學(xué)者具有很好的參考借鑒價(jià)值,下面就跟小編一起來看下吧2016-12-12asp.net UpdaeProgress的簡(jiǎn)單用法
這個(gè)控件相比其他控件,屬性少 使用簡(jiǎn)單,就先把這個(gè)控件的一般使用方法簡(jiǎn)單紀(jì)錄下2008-10-10