自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

編碼中的Adapter,不僅是一種設(shè)計(jì)模式,更是一種架構(gòu)理念與解決方案

開發(fā) 前端
關(guān)于Adapter?相關(guān)的討論與個(gè)人的理解,這里就給大家分享到這里。Adapter不僅是一個(gè)簡(jiǎn)單的具體實(shí)現(xiàn)類,也不僅僅是23種設(shè)計(jì)模式之一,更是一種問題解決的思想、一種方案設(shè)計(jì)的理念。

大家好,又見面了。

不知道大家有沒有見過或者使用過插座轉(zhuǎn)換器。我們都知道日常使用的是220v的交流電,而國(guó)外不同國(guó)家使用的電流電壓是不一樣的(比如日本使用的是110v)、且插座的接口樣式也是各不相同的(比如歐洲國(guó)家使用的是兩個(gè)小圓柱狀的插頭接口),如果我們到別的國(guó)家去旅行的時(shí)候,借助這個(gè)插座轉(zhuǎn)換器,就可以讓我們的手機(jī)充電器在國(guó)外也能正常使用了。

當(dāng)然,除了使用插座轉(zhuǎn)換器,還有個(gè)方法也可以讓我們出國(guó)之后正常的使用各種電子產(chǎn)品,那就是在當(dāng)?shù)刂匦沦I一套!顯然,這樣的成本就會(huì)非常巨大,明顯不符合我們 勤(nang)儉(zhong)持(xiu)家(se) 的特征。

看過我前面的文章的小伙伴應(yīng)該知道,我的文章中一直反復(fù)的在闡述自己的一個(gè)觀念,即“編碼源于生活” ,這里依舊不例外?,F(xiàn)實(shí)生活中的樸素哲學(xué)思維,在代碼世界中其實(shí)也無時(shí)無刻不在體現(xiàn)著。上面舉的例子,在我們的項(xiàng)目中又何嘗不是在頻繁上演此類情況呢?

我們先按照原有的業(yè)務(wù)邏輯實(shí)現(xiàn)了一套代碼,后來又來了個(gè)新的需求,如果重新開發(fā)一套需要投入大量的人力物力,所以首選方案就是去思考如何去復(fù)用已有的邏輯,以最小的代價(jià)將業(yè)務(wù)對(duì)接適配使用現(xiàn)有的邏輯去實(shí)現(xiàn)。

本篇文章中,我們就從這個(gè)“插座轉(zhuǎn)換器”來作為切入點(diǎn),聊一聊在軟件系統(tǒng)中無處不在的“插座轉(zhuǎn)換器” —— 編碼中的適配器(Adapter)。選定以Adapter為題材進(jìn)行闡述,并非是因?yàn)锳dapter在技術(shù)實(shí)現(xiàn)上有多復(fù)雜,其實(shí)Adapter真正實(shí)現(xiàn)起來是非常簡(jiǎn)單的,而且很多人有意或無意中其實(shí)也都在使用。更多的是想一起探討這種借助Adapter來復(fù)用與兼容已有邏輯的思路,以及如何利用Adapter來踐行OCP(開閉原則)的系統(tǒng)架構(gòu)設(shè)計(jì)理念。

Adapter的百媚千姿

新瓶舊酒:復(fù)用現(xiàn)成的實(shí)現(xiàn)邏輯

新瓶裝舊酒,在我們的系統(tǒng)里面是一個(gè)很“節(jié)省”的操作,可以讓我們基于一個(gè)現(xiàn)有的能力快速的封裝提供出一個(gè)全新的業(yè)務(wù)功能,當(dāng)然有的時(shí)候,系統(tǒng)現(xiàn)有的能力可能會(huì)某些方面無法完全滿足新業(yè)務(wù)的需求,需要做一些轉(zhuǎn)換適配處理。

舉個(gè)例子:

一個(gè)視頻網(wǎng)站,原先已有一個(gè)評(píng)論能力,用戶可以在視頻下方發(fā)表評(píng)論,然后評(píng)論內(nèi)容以列表的形式展示在視頻下方頁面上。現(xiàn)在需要開發(fā)一個(gè)新功能,支持視頻發(fā)送彈幕能力,并將彈幕顯示在視頻播放畫面上。

從需求功能上來說,評(píng)論與彈幕有很多相似之處。對(duì)后端而言,其處理邏輯與存儲(chǔ)數(shù)據(jù)結(jié)構(gòu)幾乎都是相同的,只是在數(shù)據(jù)列表API實(shí)現(xiàn)的時(shí)候,需要過濾出評(píng)論信息展示到評(píng)論區(qū)、或者過濾出彈幕信息顯示到視頻畫面上。但是由于彈幕信息有一些特殊的屬性,又沒法直接完全使用現(xiàn)有的評(píng)論接口,比如彈幕可能會(huì)設(shè)置顯示在屏幕的位置、彈幕的字體顏色等等。這種情況下,我們可以通過構(gòu)造個(gè)Adapter適配器的方式,在復(fù)用已有評(píng)論能力的基礎(chǔ)上,順便擴(kuò)展實(shí)現(xiàn)需要的彈幕新特性。

圖片

如上圖所示,我們可以在Adapter中封裝擴(kuò)展彈幕需要的新特性,然后對(duì)于數(shù)據(jù)存儲(chǔ)等邏輯則直接復(fù)用已有的評(píng)論功能處理邏輯,這樣就可以大大減少我們的開發(fā)工作量、后續(xù)也只需要維護(hù)一套主體代碼即可。

負(fù)重前行:兼容歷史版本

和上面討論的場(chǎng)景相反,實(shí)際開發(fā)中還有一種非常常見的情況,就是原先的時(shí)候?qū)崿F(xiàn)了一套業(yè)務(wù)邏輯,然后因?yàn)闃I(yè)務(wù)變化或者系統(tǒng)重構(gòu),需要對(duì)底層具體實(shí)現(xiàn)邏輯進(jìn)行大改。這種情況下,為了保證此前調(diào)用該API的業(yè)務(wù)可以正常使用,通常有兩種思路:

保持原先的內(nèi)容不動(dòng),完全另起爐灶全新實(shí)現(xiàn)一套,然后兩套邏輯并存,同時(shí)維護(hù);

按照新的邏輯去實(shí)現(xiàn),并將原先的對(duì)外API適配轉(zhuǎn)換對(duì)接使用新邏輯實(shí)現(xiàn)。

顯然,從成本與可維護(hù)性層面考慮,思路2更為可行、更加經(jīng)濟(jì)。

圖片

對(duì)比我們文首舉的那個(gè)“插頭轉(zhuǎn)換器”的例子,我們可以把圖中V1版本業(yè)務(wù)邏輯當(dāng)做我們國(guó)內(nèi)的手機(jī)充電插頭,而圖中綠色部分的V2新版本依賴邏輯,則是歐洲地區(qū)的圓孔墻面插座,那么如何讓國(guó)標(biāo)的扁口插頭能用上歐標(biāo)的圓孔插座呢?關(guān)鍵就是那個(gè)插頭轉(zhuǎn)換器(Adapter)。

另類心機(jī):屏蔽開源協(xié)議傳染

大家可以回想下,曾經(jīng)是否也有過從github上“借鑒”一些代碼放進(jìn)了自己的項(xiàng)目中,然后簡(jiǎn)單修改為符合自己訴求的邏輯,便當(dāng)做是自研代碼去正常使用了?不知道你是否有關(guān)注過你所拷貝的代碼所對(duì)應(yīng)的開源協(xié)議呢?要小心啦、這個(gè)看似平常的操作,也許會(huì)給項(xiàng)目埋下致命隱患!

圖片

為什么說的這么危言聳聽呢?因?yàn)橛幸恍┎惶押玫拈_源協(xié)議(比如GPL協(xié)議),會(huì)要求使用了其代碼的項(xiàng)目如果商用就必須要開源其全部源碼!而對(duì)于很多軟件公司而言,源碼便是公司的核心資產(chǎn),是公司最為核心的競(jìng)爭(zhēng)力,將源碼開源無異于是要了老板和公司的命。也許有人會(huì)對(duì)此很不屑,大家都這么干,似乎并沒有發(fā)現(xiàn)有人來追責(zé)呢?有個(gè)詞叫做“樹大招風(fēng)”,只要你的產(chǎn)品做的夠大,就一定會(huì)被盯上 —— 你品,你細(xì)品。在當(dāng)前知識(shí)版權(quán)保護(hù)越來越強(qiáng)的情況下,我們還是應(yīng)該關(guān)注并提前做好應(yīng)對(duì)這種危機(jī)出現(xiàn)的可能,避免埋下隱患。

這種情況下,可以基于Adapter的機(jī)制,實(shí)現(xiàn)棄卒保車的效果。即構(gòu)建一個(gè)適配層,然后僅將適配層進(jìn)行開源,而核心的模塊代碼中,則通過接口調(diào)用的方式使用適配層即可,這樣避免了核心模塊代碼被開源協(xié)議傳染。由于核心模塊中并沒有集成被二次改動(dòng)后的開源源碼,所以也不具有開放源碼的義務(wù)、而Adapter層沒有任何核心業(yè)務(wù)邏輯,即使開源對(duì)公司、對(duì)項(xiàng)目也沒有影響。

圖片

基于Adapter適配層的方式來切斷開源協(xié)議傳染的成功實(shí)踐,最典型的莫過于Android項(xiàng)目(AOSP)了。因?yàn)锳OSP是基于Linux kernel內(nèi)核進(jìn)行構(gòu)建的,而Linux Kernel使用的是GPL協(xié)議,那么按照要求,AOSP也需要開源其源碼。但是問題來了,如果AOSP開源源碼了,勢(shì)必導(dǎo)致所有基于Android定制的各個(gè)硬件廠商底層的設(shè)備驅(qū)動(dòng)相關(guān)的代碼也都要全部開源,顯然不會(huì)有公司愿意這么干。

為了讓各個(gè)公司可以放心的基于Android去開發(fā)自己的產(chǎn)品,AOSP將自己的協(xié)議搞成了Apache開源協(xié)議,這樣對(duì)產(chǎn)商而言就非常友好了,無需將自己的核心源碼開源。那么Google是如何做到將本來需要以GPL協(xié)議開源的AOSP給變?yōu)槭褂肁pache協(xié)議開源的呢?其實(shí)就是做了一個(gè)Adapter —— 也即HAL(Hardware Abstract Layer,硬件抽象層)。

Adapter是一種理念

關(guān)于編碼中的Adapter,常規(guī)的文檔或者資料中,往往都是指的狹義上的適配器,也就是代碼class類維度的Adapter。

我們跳出純粹的編碼層面,站到全局系統(tǒng)架構(gòu)視角去審視的時(shí)候,其實(shí)Adapter在系統(tǒng)架構(gòu)與編碼設(shè)計(jì)中是一個(gè)比較寬泛的概念。我個(gè)人更愿意Adapter看做是一種問題解決的思想、一種方案設(shè)計(jì)的理念。

根據(jù)要解決的問題level與范圍的不同,Adapter對(duì)應(yīng)的粒度與呈現(xiàn)形態(tài)也會(huì)有差異。

服務(wù)型Adapter

如果是在一個(gè)分布式微服務(wù)系統(tǒng)中,消息推送能力可以預(yù)見的會(huì)提供給很多不同的服務(wù)節(jié)點(diǎn)去調(diào)用,則可以將消息推送能力也封裝為一個(gè)對(duì)外微服務(wù),業(yè)務(wù)通過RPC或者HTTP等方式進(jìn)行遠(yuǎn)程調(diào)用。

圖片

這種是一種相對(duì)High Level的Adapter抽象使用(但抽象為服務(wù)獨(dú)立部署后,其實(shí)也不僅僅是個(gè)Adapter了),廣泛的應(yīng)用于系統(tǒng)架構(gòu)層面,是解決系統(tǒng)功能復(fù)用、業(yè)務(wù)解耦的一種有效手段。

在我此前的一篇文章中,介紹了一個(gè)構(gòu)建通用在線文檔預(yù)覽服務(wù)的實(shí)際案例,里面對(duì)“預(yù)覽編輯服務(wù)”的定位就是一個(gè)典型的服務(wù)型Adapter,如下圖所示。通過預(yù)覽編輯服務(wù)這個(gè)Adapter,將文檔預(yù)覽能力所涉及的后端對(duì)接OnlyOffice或者對(duì)接kkFileView等細(xì)節(jié)邏輯給屏蔽掉,業(yè)務(wù)服務(wù)通過Adapter進(jìn)行調(diào)用,大大簡(jiǎn)化了業(yè)務(wù)的使用復(fù)雜度,也保持了業(yè)務(wù)模塊與文檔預(yù)覽服務(wù)內(nèi)部模塊之間的耦合。

圖片

服務(wù)型Adapter著眼解決的是系統(tǒng)進(jìn)程層面的適配與統(tǒng)一封裝,自身既是一個(gè)Adapter,又是一個(gè)獨(dú)立的服務(wù),封裝內(nèi)部細(xì)節(jié)差異化的實(shí)現(xiàn),保證其它進(jìn)程服務(wù)相對(duì)簡(jiǎn)單的調(diào)用邏輯。

依賴庫(kù)型Adapter

在一些中小型項(xiàng)目中,會(huì)有若干個(gè)業(yè)務(wù)模塊中會(huì)用到消息發(fā)送的能力,但是整體體量與業(yè)務(wù)規(guī)劃層面而言,卻也無需單獨(dú)部署一個(gè)專門的消息推送服務(wù)進(jìn)程,這種情況下,可以將其封裝為一個(gè)依賴庫(kù),比如JAVA中的一個(gè)jar包,或者C++中的一個(gè)so庫(kù)文件,亦或是C#中的dll庫(kù)文件。這樣各個(gè)業(yè)務(wù)模塊可以集成此庫(kù)文件,直接進(jìn)行API調(diào)用即可。

圖片

此種類型的Adapter實(shí)現(xiàn),在很多的框架中非常常見。比如在JAVA中的SpringBoot中的日志框架,底層可以選擇是使用logback,也可以選擇切換到log4j。

代碼類Adapter

在單個(gè)項(xiàng)目模塊中,我們?yōu)榱吮3謽I(yè)務(wù)邏輯的清晰與獨(dú)立,也會(huì)通過Adapter類的方式,來解耦具體的業(yè)務(wù)邏輯。比如這里的消息推送服務(wù),如果僅當(dāng)前模塊需要使用,則可以創(chuàng)建一個(gè)獨(dú)立的Adapter類,提供接口供其他類調(diào)用,在Adapter類中完成具體邏輯的封裝實(shí)現(xiàn)。

還是以前面舉的告警通知消息發(fā)送的例子來說明,使用Adapter方式隔離消息通道與業(yè)務(wù)邏輯的實(shí)現(xiàn)UML圖如下:

圖片

代碼類的Adapter在實(shí)際項(xiàng)目中使用的場(chǎng)景非常的廣泛,是用于屏蔽代碼底層差異化邏輯的不二選擇。在總結(jié)各種實(shí)際使用場(chǎng)景與優(yōu)秀實(shí)踐的基礎(chǔ)上,演進(jìn)為23種設(shè)計(jì)模式之一的適配器模式。

下面我們一起聊一聊適配器模式。

Adapter是一種設(shè)計(jì)模式

所謂設(shè)計(jì)模式,便是將常規(guī)代碼編碼中常遇到的一些場(chǎng)景的處理方式進(jìn)行了總結(jié)與抽象,固化成一個(gè)優(yōu)秀實(shí)踐范例模板,使其整體實(shí)現(xiàn)更符合設(shè)計(jì)原則的要求。也就是說:設(shè)計(jì)模式并非是憑空捏造的,其實(shí)就是來源于常規(guī)的編碼實(shí)踐總結(jié)。

按照通俗意義上對(duì)代碼設(shè)計(jì)模式的理解,適配器模式也可以分為2種形式,即類適配器模式與對(duì)象適配器模式。

下面分別闡述下。

類適配器模式

類適配器模式整體非常的簡(jiǎn)單,涉及的角色也很少。類適配器模式中,Adapter與被適配的Adaptee之間,通過繼承的方式來實(shí)現(xiàn),其UML圖如下所示。

圖片

主要角色說明如下:

  • Adaptee:原始被適配的類,即不符合訴求需要由Adapter進(jìn)行適配的原始接口。
  • Adapter:適配器本身,也是類適配器模式的核心,用于將Adaptee適配為目標(biāo)的Target。
  • Target:期待獲取到的目標(biāo)結(jié)果。也即Adaptee經(jīng)由Adapter適配后得到的統(tǒng)一的目標(biāo)接口。

還是以前面的告警通知發(fā)送的場(chǎng)景為例,我們按照聚合的方式,演示下對(duì)應(yīng)的Adapter實(shí)現(xiàn)邏輯。

@Service
public class MsgSendAdapter extends SmsSender implements IMsgSender {
@Override
public void send(AlarmDetail detail) {
// detail轉(zhuǎn)SMS請(qǐng)求體的邏輯
SmsContent sms = convertToSmsContent(detail);
super.sendSms(sms);
}
}

上述代碼中,MsgSendAdapter繼承了SmsSender類并且實(shí)現(xiàn)了IMsgSender接口,將父類SmsSender中的sendSms接口轉(zhuǎn)換為了IMsgSender接口提供的目標(biāo)接口send(),業(yè)務(wù)可以調(diào)用IMsgSender.send()接口,實(shí)現(xiàn)對(duì)SmsSender.sendSms()邏輯的調(diào)用。

對(duì)象適配器模式

對(duì)象適配器模式與類適配器模式類似,區(qū)別點(diǎn)在于Adapter與被適配的Adaptee之間非繼承關(guān)系,而是對(duì)象組合關(guān)系。其UML圖如下:

圖片

按照對(duì)象適配器的設(shè)計(jì)思路,其代碼可以如下方式來實(shí)現(xiàn):

@Service
public class MsgSendAdapter implements IMsgSender {
@Autowired
private SmsSender smsSender;

@Override
public void send(AlarmDetail detail) {
// detail轉(zhuǎn)SMS請(qǐng)求體的邏輯
SmsContent sms = convertToSmsContent(detail);
smsSender.sendSms(sms);
}
}

上述代碼中,MsgSendAdapter類中以組合的方式持有SmsSender對(duì)象(Adaptee),相比較類適配器的繼承邏輯,靈活性更高,所以對(duì)象適配器要更加的靈活與實(shí)用(其實(shí)在架構(gòu)設(shè)計(jì)領(lǐng)域也一直有一種觀點(diǎn)叫“組合優(yōu)于繼承”,因?yàn)槔^承打破了面向?qū)ο蟮姆庋b)。

總結(jié)回顧

好啦,關(guān)于Adapter相關(guān)的討論與個(gè)人的理解,這里就給大家分享到這里。Adapter不僅是一個(gè)簡(jiǎn)單的具體實(shí)現(xiàn)類,也不僅僅是23種設(shè)計(jì)模式之一,更是一種問題解決的思想、一種方案設(shè)計(jì)的理念。

關(guān)于本篇文檔中的內(nèi)容,不知道屏幕前的各位小伙伴是否在項(xiàng)目中有使用過Adapter或者Adapter模式來幫助自己實(shí)現(xiàn)某些功能呢?是否對(duì)Adapter還有一些別的獨(dú)到見解呢?

責(zé)任編輯:武曉燕 來源: 架構(gòu)悟道
相關(guān)推薦

2022-09-22 07:50:12

數(shù)據(jù)庫(kù)運(yùn)營(yíng)商日檢

2022-06-16 15:36:37

攻擊面管理ASM

2022-10-27 14:32:47

測(cè)試驅(qū)動(dòng)思維

2013-11-29 09:18:39

GartnerBYOD應(yīng)用戰(zhàn)略

2023-07-03 19:40:21

系統(tǒng)設(shè)計(jì)模式

2024-03-29 11:13:17

云計(jì)算人工智能

2017-07-05 14:09:04

系統(tǒng)設(shè)計(jì)與架構(gòu)java云計(jì)算

2022-06-21 10:04:25

比特幣去中心化金融體系

2019-07-22 15:59:21

2012-01-17 11:02:39

2020-12-09 10:15:34

Pythonweb代碼

2020-12-23 10:10:23

Pythonweb代碼

2022-06-22 09:44:41

Python文件代碼

2022-07-07 10:33:27

Python姿勢(shì)代碼

2021-01-06 08:05:32

JavaSocke粘包

2017-02-28 11:13:36

華為

2015-09-17 09:08:08

2022-03-01 09:58:10

高并發(fā)架構(gòu)開發(fā)

2011-03-01 09:43:13

MapReduce架構(gòu)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)