亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

(第Ⅲ部分 結(jié)構(gòu)型模式篇) 第7章 適配器模式(Ad

系統(tǒng) 1738 0
——.NET設(shè)計模式系列之八
Terrylee 2006 2
概述
在軟件系統(tǒng)中,由于應(yīng)用環(huán)境的變化,常常需要將“一些現(xiàn)存的對象”放在新的環(huán)境中應(yīng)用,但是新環(huán)境要求的接口是這些現(xiàn)存對象所不滿足的。那么如何應(yīng)對這種“遷移的變化”?如何既能利用現(xiàn)有對象的良好實現(xiàn),同時又能滿足新的應(yīng)用環(huán)境所要求的接口?這就是本文要說的 Adapter 模式。
意圖
將一個類的接口轉(zhuǎn)換成客戶希望的另外一個接口。 Adapter 模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
結(jié)構(gòu)圖
1 類的 Adapter 模式結(jié)構(gòu)圖
2 對象的 Adapter 模式結(jié)構(gòu)圖
生活中的例子
適配器模式允許將一個類的接口轉(zhuǎn)換成客戶期望的另一個接口,使得原本由于接口不兼容而不能一起工作的類可以一起工作。扳手提供了一個適配器的例子。一個孔套在棘齒上,棘齒的每個邊的尺寸是相同的。在美國典型的邊長為 1/2'' 1/4'' 。顯然,如果不使用一個適配器的話, 1/2'' 的棘齒不能適合 1/4'' 的孔。一個 1/2'' 1/4'' 的適配器具有一個 1/2'' 的陰槽來套上一個 1/2'' 的齒,同時有一個 1/4 的陽槽來卡入 1/4'' 的扳手。
3 使用扳手適配器例子的適配器對象圖
適配器模式解說
我們還是以日志記錄程序為例子說明 Adapter 模式。現(xiàn)在有這樣一個場景:假設(shè)我們在軟件開發(fā)中要使用一個第三方的日志記錄工具,該日志記錄工具支持數(shù)據(jù)庫日志記錄 DatabaseLog 和文本文件記錄 FileLog 兩種方式,它提供給我們的 API 接口是 Write() 方法,使用方法如下:
Log . Write( "Logging Message!" );
當(dāng)軟件系統(tǒng)開發(fā)進行到一半時,處于某種原因不能繼續(xù)使用該日志記錄工具了,需要采用另外一個日志記錄工具,它同樣也支持數(shù)據(jù)庫日志記錄 DatabaseLog 和文本文件記錄 FileLog 兩種方式,只不過它提供給我們的 API 接口是 WriteLog() 方法,使用方法如下:
Log . WriteLog( "Logging Message!" );
該日志記錄工具的類結(jié)構(gòu)圖如下:
4 日志記錄工具類結(jié)構(gòu)圖
它的實現(xiàn)代碼如下:
public abstract class LogAdaptee
{
public abstract void WriteLog();
}
public class DatabaseLog:LogAdaptee
{
public override void WriteLog()
{
Console . WriteLine( "Called WriteLog Method" );
}
}
public class FileLog:LogAdaptee
{
public override void WriteLog()
{
Console . WriteLine( "Called WriteLog Method" );
}
}
在我們開發(fā)完成的應(yīng)用程序中日志記錄接口中(不妨稱之為 ILogTarget 接口,在本例中為了更加清楚地說明,在命名上采用了 Adapter 模式中的相關(guān)角色名字),卻用到了大量的 Write() 方法,程序已經(jīng)全部通過了測試,我們不能去修改該接口。代碼如下:
public interface ILogTarget
{
void Write();
}
這時也許我們會想到修改現(xiàn)在的日志記錄工具的 API 接口,但是由于版權(quán)等原因我們不能夠修改它的源代碼,此時 Adapter 模式便可以派上用場了。下面我們通過 Adapter 模式來使得該日志記錄工具能夠符合我們當(dāng)前的需求。
前面說過, Adapter 模式有兩種實現(xiàn)形式的實現(xiàn)結(jié)構(gòu),首先來看一下類適配器如何實現(xiàn)。現(xiàn)在唯一可行的辦法就是在程序中引入新的類型,讓它去繼承 LogAdaptee 類,同時又實現(xiàn)已有的 ILogTarget 接口。由于 LogAdaptee 有兩種類型的方式,自然我們要引入兩個分別為 DatabaseLogAdapter FileLogAdapter 的類。
5 引入類適配器后的結(jié)構(gòu)圖
實現(xiàn)代碼如下:
public class DatabaseLogAdapter:DatabaseLog,ILogTarget
{
public void Write()
{
WriteLog();
}
}
public class FileLogAdapter:FileLog,ILogTarget
{
public void Write()
{
this . WriteLog();
}
}
這里需要注意的一點是我們?yōu)槊恳环N日志記錄方式都編寫了它的適配類,那為什么不能為抽象類 LogAdaptee 來編寫一個適配類呢?因為 DatabaseLog FileLog 雖然同時繼承于抽象類 LogAdaptee ,但是它們具體的 WriteLog() 方法的實現(xiàn)是不同的。只有繼承于該具體類,才能保留其原有的行為。
我們看一下這時客戶端的程序的調(diào)用方法:
public class App
{
public static void Main()
{
ILogTarget dbLog = new DatabaseLogAdapter();
dbLog . Write( "Logging Database..." );
ILogTarget fileLog = new FileLogAdapter();
fileLog . Write( "Logging File..." );
}
}
下面看一下如何通過對象適配器的方式來達到我們適配的目的。對象適配器是采用對象組合而不是使用繼承,類結(jié)構(gòu)圖如下:
6 引入對象適配器后的結(jié)構(gòu)圖
實現(xiàn)代碼如下:
public class LogAdapter:ILogTarget
{
private LogAdaptee _adaptee;
public LogAdapter(LogAdaptee adaptee)
{
this . _adaptee = adaptee;
}
public void Write()
{
_adaptee . WriteLog();
}
}
與類適配器相比較,可以看到最大的區(qū)別是適配器類的數(shù)量減少了,不再需要為每一種具體的日志記錄方式來創(chuàng)建一個適配器類。同時可以看到,引入對象適配器后,適配器類不再依賴于具體的 DatabaseLog 類和 FileLog 類,更好的實現(xiàn)了松耦合。
再看一下客戶端程序的調(diào)用方法:
public class App
{
public static void Main()
{
ILogTarget dbLog = new LogAdapter( new DatabaseLog());
dbLog . Write( "Logging Database..." );
ILogTarget fileLog = new LogAdapter( new FileLog());
fileLog . Write( "Logging Database..." );
}
}
通過 Adapter 模式,我們很好的實現(xiàn)了對現(xiàn)有組件的復(fù)用。對比以上兩種適配方式,可以總結(jié)出,在類適配方式中,我們得到的適配器類 DatabaseLogAdapter FileLogAdapter 具有它所繼承的父類的所有的行為,同時也具有接口 ILogTarget 的所有行為,這樣其實是違背了面向?qū)ο笤O(shè)計原則中的類的單一職責(zé)原則,而對象適配器則更符合面向?qū)ο蟮木瘢栽趯嶋H應(yīng)用中不太推薦類適配這種方式。再換個角度來看類適配方式,假設(shè)我們要適配出來的類在記錄日志時同時寫入文件和數(shù)據(jù)庫,那么用對象適配器我們會這樣去寫:
public class LogAdapter:ILogTarget
{
private LogAdaptee _adaptee1;
private LogAdaptee _adaptee2;
public LogAdapter(LogAdaptee adaptee1,LogAdaptee adaptee2)
{
this . _adaptee1 = adaptee1;
this . _adaptee2 = adaptee2;
}
public void Write()
{
_adaptee1 . WriteLog();
_adaptee2 . WriteLog();
}
}
如果改用類適配器,難道這樣去寫:
public class DatabaseLogAdapter:DatabaseLog,FileLog,ILogTarget
{
public void Write()
{
//WriteLog();
}
}
顯然是不對的,這樣的解釋雖說有些牽強,也足以說明一些問題,當(dāng)然了并不是說類適配器在任何情況下都不使用,針對開發(fā)場景不同,某些時候還是可以用類適配器的方式。
.NET 中的適配器模式
1 .Adapter模式在.NET Framework中的一個最大的應(yīng)用就是 COM Interop 。COM Interop就好像是COM和.NET之間的一條紐帶,一座橋梁。我們知道,COM組件對象與.NET類對象是完全不同的,但為了使COM客戶程序象調(diào)用COM組件一樣調(diào)用.NET對象,使.NET程序
象使用.NET對象一樣使用COM組件,微軟在處理方式上采用了Adapter模式,對COM對象進行包裝,這個包裝類就是RCW(Runtime Callable Wrapper)。RCW實際上是runtime生成的一個.NET類,它包裝了COM組件的方法,并內(nèi)部實現(xiàn)對COM組件的調(diào)用。如下圖所示:
圖7 .NET程序與COM互相調(diào)用示意圖
2 ..NET中的另一個Adapter模式的應(yīng)用就是DataAdapter。ADO.NET為統(tǒng)一的數(shù)據(jù)訪問提供了多個接口和基類,其中最重要的接口之一是IdataAdapter。與之相對應(yīng)的DataAdpter是一個抽象類,它是ADO.NET與具體數(shù)據(jù)庫操作之間的數(shù)據(jù)適配器的基類。DataAdpter起到了數(shù)據(jù)庫到DataSet橋接器的作用,使應(yīng)用程序的數(shù)據(jù)操作統(tǒng)一到DataSet上,而與具體的數(shù)據(jù)庫類型無關(guān)。甚至可以針對特殊的數(shù)據(jù)源編制自己的DataAdpter,從而使我們的應(yīng)用程序與這些特殊的數(shù)據(jù)源相兼容。注意這是一個適配器的變體。
實現(xiàn)要點
1 Adapter 模式主要應(yīng)用于“希望復(fù)用一些現(xiàn)存的類,但是接口又與復(fù)用環(huán)境要求不一致的情況”,在遺留代碼復(fù)用、類庫遷移等方面非常有用。
2 Adapter 模式有對象適配器和類適配器兩種形式的實現(xiàn)結(jié)構(gòu),但是類適配器采用“多繼承”的實現(xiàn)方式,帶來了不良的高耦合,所以一般不推薦使用。對象適配器采用“對象組合”的方式,更符合松耦合精神。
3 Adapter 模式的實現(xiàn)可以非常的靈活,不必拘泥于 GOF23 中定義的兩種結(jié)構(gòu)。例如,完全可以將 Adapter 模式中的“現(xiàn)存對象”作為新的接口方法參數(shù),來達到適配的目的。
4 Adapter 模式本身要求我們盡可能地使用“面向接口的編程”風(fēng)格,這樣才能在后期很方便的適配。 [ 以上幾點引用自 MSDN WebCast]
效果
對于類適配器:
1 .用一個具體的 Adapter 類對 Adaptee Taget 進行匹配。結(jié)果是當(dāng)我們想要匹配一個類以及所有它的子類時,類 Adapter 將不能勝任工作。
2 .使得 Adapter 可以重定義 Adaptee 的部分行為,因為 Adapter Adaptee 的一個子類。
3 .僅僅引入了一個對象,并不需要額外的指針一間接得到 Adaptee.
對于對象適配器:
1 .允許一個 Adapter 與多個 Adaptee ,即 Adaptee 本身以及它的所有子類(如果有子類的話)同時工作。 Adapter 也可以一次給所有的 Adaptee 添加功能。
2 .使得重定義 Adaptee 的行為比較困難。這就需要生成 Adaptee 的子類并且使得 Adapter 引用這個子類而不是引用 Adaptee 本身。
適用性
在以下各種情況下使用適配器模式:
1 .系統(tǒng)需要使用現(xiàn)有的類,而此類的接口不符合系統(tǒng)的需要。
2 .想要建立一個可以重復(fù)使用的類,用于與一些彼此之間沒有太大關(guān)聯(lián)的一些類,包括一些可能在將來引進的類一起工作。這些源類不一定有很復(fù)雜的接口。
3 .(對對象適配器而言)在設(shè)計里,需要改變多個已有子類的接口,如果使用類的適配器模式,就要針對每一個子類做一個適配器,而這不太實際。
總結(jié)
總之,通過運用 Adapter 模式,就可以充分享受進行類庫遷移、類庫重用所帶來的樂趣。
參考資料
閻宏,《 Java 與模式》,電子工業(yè)出版社
James W. Cooper ,《 C# 設(shè)計模式》,電子工業(yè)出版社
Alan Shalloway James R. Trott ,《 Design Patterns Explained 》,中國電力出版社
MSDN WebCast C# 面向?qū)ο笤O(shè)計模式縱橫談 (7) Adapter 適配器模式 ( 結(jié)構(gòu)型模式 )

(第Ⅲ部分 結(jié)構(gòu)型模式篇) 第7章 適配器模式(Adapter Pattern)


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 久草日韩 | 欧美黄页网 | 亚洲视频一区在线观看 | 欧美成人香蕉在线观看 | 国产亚洲精品一区久久 | 久久午夜一区二区 | 日日骚 | 日韩毛片最新看 | 国产未成女年一区二区 | 欧美日韩在线播放 | 在线性视频 | 在线视频自拍 | 中文字幕在线观看日本 | 欧美成人性色xxxx视频 | 99国产国人青青视频在线观看 | 国产图片综合 | 国产在线观看精品香蕉v区 国产在线观看美女福利精 国产在线观看午夜不卡 | 一级肉体毛片视频免费看看 | 久草在线视频看看 | 成人在线黄色 | 色爱综合网欧美 | 精品视频网 | 91综合精品网站久久 | xxx中国www免费| 欧美高清69hd | 久久精品中文字幕不卡一二区 | 99久久精品免费视频 | 久久久久久综合一区中文字幕 | 免费中文字幕视频 | 深夜成人性视频免费看 | 337p日本欧洲亚洲大胆艺术 | 欧美亚洲国产日韩综合在线播放 | 性丰满妇女free性性性 | 亚洲国产成人在线视频 | 一级特黄aa大片一又好看 | 欧美黄色免费在线观看 | 天天综合色网 | 亚洲欧美综合网站 | 欧美videos粗暴高清性 | 久久精品这里精品 | 91精品国产免费久久久久久青草 |