一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

實(shí)踐GoF的23種設(shè)計(jì)模式:適配器模式

元閏子的邀請(qǐng) ? 來源:元閏子的邀請(qǐng) ? 2023-12-10 14:00 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

上一篇:【Go實(shí)現(xiàn)】實(shí)踐GoF的23種設(shè)計(jì)模式:備忘錄模式

簡(jiǎn)單的分布式應(yīng)用系統(tǒng)(示例代碼工程):https://github.com/ruanrunxue/Practice-Design-Pattern--Go-Implementation

簡(jiǎn)介

適配器模式Adapter)是最常用的結(jié)構(gòu)型模式之一,在現(xiàn)實(shí)生活中,適配器模式也是處處可見,比如電源插頭轉(zhuǎn)換器,它可以讓英式的插頭工作在中式的插座上。

GoF 對(duì)它的定義如下:

Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.

簡(jiǎn)單來說,就是適配器模式讓原本因?yàn)?a target="_blank">接口不匹配而無(wú)法一起工作的兩個(gè)類/結(jié)構(gòu)體能夠一起工作

適配器模式所做的就是將一個(gè)接口Adaptee,通過適配器Adapter轉(zhuǎn)換成 Client 所期望的另一個(gè)接口Target來使用,實(shí)現(xiàn)原理也很簡(jiǎn)單,就是Adapter通過實(shí)現(xiàn)Target接口,并在對(duì)應(yīng)的方法中調(diào)用Adaptee的接口實(shí)現(xiàn)。

31f2a122-970e-11ee-8b88-92fbcf53809c.png

UML 結(jié)構(gòu)

3228c7ac-970e-11ee-8b88-92fbcf53809c.png

場(chǎng)景上下文

在簡(jiǎn)單的分布式應(yīng)用系統(tǒng)(示例代碼工程)中,db 模塊用來存儲(chǔ)服務(wù)注冊(cè)信息和系統(tǒng)監(jiān)控?cái)?shù)據(jù),它是一個(gè) key-value 數(shù)據(jù)庫(kù)。在訪問者模式中,我們?yōu)樗鼘?shí)現(xiàn)了 Table 的按列查詢功能;同時(shí),我們也為它實(shí)現(xiàn)了簡(jiǎn)單的 SQL 查詢功能(將會(huì)在解釋器模式中介紹),查詢的結(jié)果是SqlResult結(jié)構(gòu)體,它提供一個(gè)toMap方法將結(jié)果轉(zhuǎn)換成map。

為了方便用戶使用,我們將實(shí)現(xiàn)在終端控制臺(tái)上提供人機(jī)交互的能力,如下所示,用戶輸入 SQL 語(yǔ)句,后臺(tái)返回查詢結(jié)果:

322f4dde-970e-11ee-8b88-92fbcf53809c.png

終端控制臺(tái)的具體實(shí)現(xiàn)為Console,為了提供可擴(kuò)展的查詢結(jié)果顯示樣式,我們?cè)O(shè)計(jì)了ConsoleRender接口,但因SqlResult并未實(shí)現(xiàn)該接口,所以Console無(wú)法直接渲染SqlResult的查詢結(jié)果。

32472d1e-970e-11ee-8b88-92fbcf53809c.png

為此,我們需要實(shí)現(xiàn)一個(gè)適配器,讓Console能夠通過適配器將SqlResult的查詢結(jié)果渲染出來。示例中,我們?cè)O(shè)計(jì)了適配器TableRender,它實(shí)現(xiàn)了ConsoleRender接口,并以表格的形式渲染出查詢結(jié)果,如前文所示。

327214ac-970e-11ee-8b88-92fbcf53809c.png

代碼實(shí)現(xiàn)

//demo/db/sql.go
packagedb

//AdapteeSQL語(yǔ)句執(zhí)行返回的結(jié)果,并未實(shí)現(xiàn)Target接口
typeSqlResultstruct{
fields[]string
vals[]interface{}
}

func(s*SqlResult)Add(fieldstring,recordinterface{}){
s.fields=append(s.fields,field)
s.vals=append(s.vals,record)
}

func(s*SqlResult)ToMap()map[string]interface{}{
results:=make(map[string]interface{})
fori,f:=ranges.fields{
results[f]=s.vals[i]
}
returnresults
}

//demo/db/console.go
packagedb

//Client終端控制臺(tái)
typeConsolestruct{
dbDb
}

//Output調(diào)用ConsoleRender完成對(duì)查詢結(jié)果的渲染輸出
func(c*Console)Output(renderConsoleRender){
fmt.Println(render.Render())
}

//Target接口,控制臺(tái)db查詢結(jié)果渲染接口
typeConsoleRenderinterface{
Render()string
}

//TableRender表格形式的查詢結(jié)果渲染Adapter
//關(guān)鍵點(diǎn)1:定義Adapter結(jié)構(gòu)體/類
typeTableRenderstruct{
//關(guān)鍵點(diǎn)2:在Adapter中聚合Adaptee,這里是把SqlResult作為TableRender的成員變量
result*SqlResult
}

//關(guān)鍵點(diǎn)3:實(shí)現(xiàn)Target接口,這里是實(shí)現(xiàn)了ConsoleRender接口
func(t*TableRender)Render()string{
//關(guān)鍵點(diǎn)4:在Target接口實(shí)現(xiàn)中,調(diào)用Adaptee的原有方法實(shí)現(xiàn)具體的業(yè)務(wù)邏輯
vals:=t.result.ToMap()
varheader[]string
vardata[]string
forkey,val:=rangevals{
header=append(header,key)
data=append(data,fmt.Sprintf("%v",val))
}
builder:=&strings.Builder{}
table:=tablewriter.NewWriter(builder)
table.SetHeader(header)
table.Append(data)
table.Render()
returnbuilder.String()
}

//這里是另一個(gè)Adapter,實(shí)現(xiàn)了將error渲染的功能
typeErrorRenderstruct{
errerror
}

func(e*ErrorRender)Render()string{
returne.err.Error()
}

客戶端這么使用:

func(c*Console)Start(){
fmt.Println("welcometoDemoDB,enterexittoend!")
fmt.Println(">pleaseenterasqlexpression:")
fmt.Print(">")
scanner:=bufio.NewScanner(os.Stdin)
forscanner.Scan(){
sql:=scanner.Text()
ifsql=="exit"{
break
}
result,err:=c.db.ExecSql(sql)
iferr==nil{
//關(guān)鍵點(diǎn)5:在需要Target接口的地方,傳入適配器Adapter實(shí)例,其中創(chuàng)建Adapter實(shí)例時(shí)需要傳入Adaptee實(shí)例
c.Output(NewTableRender(result))
}else{
c.Output(NewErrorRender(err))
}
fmt.Println(">pleaseenterasqlexpression:")
fmt.Print(">")
}
}

在已經(jīng)有了 Target 接口(ConsoleRender)和 Adaptee(SqlResult)的前提下,總結(jié)實(shí)現(xiàn)適配器模式的幾個(gè)關(guān)鍵點(diǎn):

  1. 定義 Adapter 結(jié)構(gòu)體/類,這里是TableRender結(jié)構(gòu)體。
  2. 在 Adapter 中聚合 Adaptee,這里是把SqlResult作為TableRender的成員變量。
  3. Adapter 實(shí)現(xiàn) Target 接口,這里是TableRender實(shí)現(xiàn)了ConsoleRender接口。
  4. 在 Target 接口實(shí)現(xiàn)中,調(diào)用 Adaptee 的原有方法實(shí)現(xiàn)具體的業(yè)務(wù)邏輯,這里是在TableRender.Render()調(diào)用SqlResult.ToMap()方法,得到查詢結(jié)果,然后再對(duì)結(jié)果進(jìn)行渲染。
  5. 在 Client 需要 Target 接口的地方,傳入適配器 Adapter 實(shí)例,其中創(chuàng)建 Adapter 實(shí)例時(shí)傳入 Adaptee 實(shí)例。這里是在NewTableRender()創(chuàng)建TableRender實(shí)例時(shí),傳入SqlResult作為入?yún)?,隨后將TableRender實(shí)例傳入Console.Output()方法。

擴(kuò)展

適配器模式在 Gin 中的運(yùn)用

Gin 是一個(gè)高性能的 Web 框架,它的常見用法如下:

//用戶自定義的請(qǐng)求處理函數(shù),類型為gin.HandlerFunc
funcmyGinHandler(c*gin.Context){
...//具體處理請(qǐng)求的邏輯
}

funcmain(){
//創(chuàng)建默認(rèn)的route引擎,類型為gin.Engine
r:=gin.Default()
//route定義
r.GET("/my-route",myGinHandler)
//route引擎啟動(dòng)
r.Run()
}

在實(shí)際運(yùn)用場(chǎng)景中,可能存在這種情況。用戶起初的 Web 框架使用了 Go 原生的net/http,使用場(chǎng)景如下:

//用戶自定義的請(qǐng)求處理函數(shù),類型為http.Handler
funcmyHttpHandler(whttp.ResponseWriter,r*http.Request){
...//具體處理請(qǐng)求的邏輯
}

funcmain(){
//route定義
http.HandleFunc("/my-route",myHttpHandler)
//route啟動(dòng)
http.ListenAndServe(":8080",nil)
}

因性能問題,當(dāng)前客戶準(zhǔn)備切換至 Gin 框架,顯然,myHttpHandler因接口不兼容,不能直接注冊(cè)到gin.Default()上。為了方便用戶,Gin 框架提供了一個(gè)適配器gin.WrapH,可以將http.Handler類型轉(zhuǎn)換成gin.HandlerFunc類型,它的定義如下:

//WrapHisahelperfunctionforwrappinghttp.HandlerandreturnsaGinmiddleware.
funcWrapH(hhttp.Handler)HandlerFunc{
returnfunc(c*Context){
h.ServeHTTP(c.Writer,c.Request)
}
}

使用方法如下:

//用戶自定義的請(qǐng)求處理函數(shù),類型為http.Handler
funcmyHttpHandler(whttp.ResponseWriter,r*http.Request){
...//具體處理請(qǐng)求的邏輯
}

funcmain(){
//創(chuàng)建默認(rèn)的route引擎
r:=gin.Default()
//route定義
r.GET("/my-route",gin.WrapH(myHttpHandler))
//route引擎啟動(dòng)
r.Run()
}

在這個(gè)例子中,gin.Engine就是 Client,gin.HandlerFunc是 Target 接口,http.Handler是 Adaptee,gin.WrapH是 Adapter。這是一個(gè) Go 風(fēng)格的適配器模式實(shí)現(xiàn),以更為簡(jiǎn)潔的func替代了struct

典型應(yīng)用場(chǎng)景

  • 將一個(gè)接口 A 轉(zhuǎn)換成用戶希望的另外一個(gè)接口 B,這樣就能使原來不兼容的接口 A 和接口 B 相互協(xié)作。
  • 老系統(tǒng)的重構(gòu)。在不改變?cè)薪涌诘那闆r下,讓老接口適配到新的接口。

優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

  1. 能夠使 Adaptee 和 Target 之間解耦。通過引入新的 Adapter 來適配 Target,Adaptee 無(wú)須修改,符合開閉原則。
  2. 靈活性好,能夠很方便地通過不同的適配器來適配不同的接口。

缺點(diǎn)

  1. 增加代碼復(fù)雜度。適配器模式需要新增適配器,如果濫用會(huì)導(dǎo)致系統(tǒng)的代碼復(fù)雜度增大。

與其他模式的關(guān)聯(lián)

適配器模式 和裝飾者模式、代理模式在 UML 結(jié)構(gòu)上具有一定的相似性。但適配器模式改變?cè)袑?duì)象的接口,但不改變?cè)泄δ?;而裝飾者模式和代理模式則在不改變接口的情況下,增強(qiáng)原有對(duì)象的功能。

文章配圖

可以在用Keynote畫出手繪風(fēng)格的配圖中找到文章的繪圖方法。


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 模塊
    +關(guān)注

    關(guān)注

    7

    文章

    2788

    瀏覽量

    50346
  • 適配器
    +關(guān)注

    關(guān)注

    9

    文章

    2054

    瀏覽量

    69711
  • 數(shù)據(jù)庫(kù)
    +關(guān)注

    關(guān)注

    7

    文章

    3926

    瀏覽量

    66194

原文標(biāo)題:【Go實(shí)現(xiàn)】實(shí)踐GoF的23種設(shè)計(jì)模式:適配器模式

文章出處:【微信號(hào):yuanrunzi,微信公眾號(hào):元閏子的邀請(qǐng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    適配器模式和代理模式的區(qū)別

    對(duì)象可以在客戶端和目標(biāo)對(duì)象之間起到中介的作用,這樣起到了中介的作用和保護(hù)了目標(biāo)對(duì)象的作用。 ?。?)高擴(kuò)展性    適配器模式  在計(jì)算機(jī)編程中,適配器模式(有時(shí)候也稱包裝樣式或者包裝
    發(fā)表于 10-22 15:17

    適配器模式實(shí)現(xiàn)

    依賴圖4.2、創(chuàng)建動(dòng)畫接口4.3、接口的適配器4.4、適配器的子類4.5、客戶端測(cè)試類4.6、該模式實(shí)踐第五章 適
    發(fā)表于 09-15 07:11

    適配器模式的作用

    適配器模式的作用是解決兩個(gè)軟件實(shí)體間的接口不兼容的問題。使用適配器模式之后,原本由于接口不兼容而不能工作的兩個(gè)軟件實(shí)體可以一起工作。港式插頭轉(zhuǎn)換器
    發(fā)表于 11-11 06:30

    缺省適配器模式基本概念

    在這一節(jié)我們就看一看第一類:缺省適配器模式一、缺省適配器模式基本概念1.1 說明當(dāng)不需要全部實(shí)現(xiàn)接口提供的方法時(shí),可以設(shè)計(jì)一個(gè)適配器抽象類實(shí)
    發(fā)表于 11-11 07:53

    對(duì)象適配器模式基本概念

    在這一節(jié)我們就看一看第一類:對(duì)象適配器模式一、對(duì)象適配器模式基本概念1.1 說明對(duì)象適配器模式
    發(fā)表于 11-11 07:09

    什么是硬件適配器模式

    硬件適配器模式提供一方法,使已經(jīng)存在的硬件接口能適應(yīng)應(yīng)用期望。當(dāng)應(yīng)用需要使用一個(gè)接口而硬件提供另一時(shí),硬件適配器
    發(fā)表于 12-21 07:55

    適配器模式的本質(zhì)及分類

    什么是適配器 在計(jì)算機(jī)編程中,適配器模式(有時(shí)候也稱包裝樣式或者包裝)把一個(gè)類的接口變換成客戶端所期待的另一接口,從而使原本因接口不匹配而無(wú)法在一起工作的兩個(gè)類能夠在一起工作。一個(gè)
    發(fā)表于 10-18 15:06 ?3394次閱讀

    適配器模式、裝飾器模式、代理模式的區(qū)別

    適配器模式、裝飾器模式、代理模式都屬于設(shè)計(jì)模式中的結(jié)構(gòu)型模式,結(jié)構(gòu)型設(shè)計(jì)
    發(fā)表于 10-18 15:53 ?1.7w次閱讀
    <b class='flag-5'>適配器</b><b class='flag-5'>模式</b>、裝飾器<b class='flag-5'>模式</b>、代理<b class='flag-5'>模式</b>的區(qū)別

    適配器模式和代理模式的區(qū)別

    適配器模式適配器模式有時(shí)候也稱包裝樣式或者包裝。將一個(gè)類的接口轉(zhuǎn)接成用戶所期待的。代理模式:為其他對(duì)象提供一
    發(fā)表于 01-12 11:56 ?5399次閱讀
    <b class='flag-5'>適配器</b><b class='flag-5'>模式</b>和代理<b class='flag-5'>模式</b>的區(qū)別

    java適配器模式實(shí)例

    java適配器模式將一個(gè)類的接口轉(zhuǎn)換成客戶想要的另一個(gè)接口,適配器模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。 適配器
    發(fā)表于 01-15 11:00 ?3928次閱讀

    JavaScript設(shè)計(jì)模式適配器模式

    適配器模式的作用是解決兩個(gè)軟件實(shí)體間的接口不兼容的問題。使用適配器模式之后,原本由于接口不兼容而不能工作的兩個(gè)軟件實(shí)體可以一起工作。港式插頭轉(zhuǎn)換器
    發(fā)表于 11-06 16:21 ?5次下載
    JavaScript設(shè)計(jì)<b class='flag-5'>模式</b>之<b class='flag-5'>適配器</b><b class='flag-5'>模式</b>

    大話設(shè)計(jì)模式之愛你一萬(wàn)年:第六章 結(jié)構(gòu)型模式適配器模式:i7愛妻:為愛找份工作:3.適配器模式之對(duì)象適配器

    在這一節(jié)我們就看一看第一類:對(duì)象適配器模式一、對(duì)象適配器模式基本概念1.1 說明對(duì)象適配器模式
    發(fā)表于 11-06 19:51 ?12次下載
    大話設(shè)計(jì)<b class='flag-5'>模式</b>之愛你一萬(wàn)年:第六章 結(jié)構(gòu)型<b class='flag-5'>模式</b>:<b class='flag-5'>適配器</b><b class='flag-5'>模式</b>:i7愛妻:為愛找份工作:3.<b class='flag-5'>適配器</b><b class='flag-5'>模式</b>之對(duì)象<b class='flag-5'>適配器</b>

    設(shè)計(jì)模式-適配器模式-以電壓適配器為例

    超級(jí)鏈接: Java常用設(shè)計(jì)模式的實(shí)例學(xué)習(xí)系列-緒論參考:《HeadFirst設(shè)計(jì)模式》1.關(guān)于適配器模式適配器
    發(fā)表于 11-07 09:36 ?17次下載
    設(shè)計(jì)<b class='flag-5'>模式</b>-<b class='flag-5'>適配器</b><b class='flag-5'>模式</b>-以電壓<b class='flag-5'>適配器</b>為例

    設(shè)計(jì)模式中什么是適配器模式?

    適配器模式(Adapter),將一個(gè)類的接口適配成用戶所期待的。
    的頭像 發(fā)表于 08-02 10:00 ?1126次閱讀
    設(shè)計(jì)<b class='flag-5'>模式</b>中什么是<b class='flag-5'>適配器</b><b class='flag-5'>模式</b>?

    實(shí)踐GoF23設(shè)計(jì)模式:解釋器模式

    解釋器模式(Interpreter Pattern)應(yīng)該是 GoF23 設(shè)計(jì)模式中使用頻率最少的一
    的頭像 發(fā)表于 04-01 11:01 ?983次閱讀
    <b class='flag-5'>實(shí)踐</b><b class='flag-5'>GoF</b>的<b class='flag-5'>23</b><b class='flag-5'>種</b>設(shè)計(jì)<b class='flag-5'>模式</b>:解釋器<b class='flag-5'>模式</b>