99精品伊人亚洲|最近国产中文炮友|九草在线视频支援|AV网站大全最新|美女黄片免费观看|国产精品资源视频|精彩无码视频一区|91大神在线后入|伊人终合在线播放|久草综合久久中文

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

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

實踐GoF的23種設計模式:適配器模式

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

掃碼添加小助手

加入工程師交流群

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

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

簡介

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

GoF 對它的定義如下:

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

簡單來說,就是適配器模式讓原本因為接口不匹配而無法一起工作的兩個類/結構體能夠一起工作。

適配器模式所做的就是將一個接口Adaptee,通過適配器Adapter轉換成 Client 所期望的另一個接口Target來使用,實現(xiàn)原理也很簡單,就是Adapter通過實現(xiàn)Target接口,并在對應的方法中調用Adaptee的接口實現(xiàn)。

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

UML 結構

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

場景上下文

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

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

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

終端控制臺的具體實現(xiàn)為Console,為了提供可擴展的查詢結果顯示樣式,我們設計了ConsoleRender接口,但因SqlResult并未實現(xiàn)該接口,所以Console無法直接渲染SqlResult的查詢結果。

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

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

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

代碼實現(xiàn)

//demo/db/sql.go
packagedb

//AdapteeSQL語句執(zhí)行返回的結果,并未實現(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終端控制臺
typeConsolestruct{
dbDb
}

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

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

//TableRender表格形式的查詢結果渲染Adapter
//關鍵點1:定義Adapter結構體/類
typeTableRenderstruct{
//關鍵點2:在Adapter中聚合Adaptee,這里是把SqlResult作為TableRender的成員變量
result*SqlResult
}

//關鍵點3:實現(xiàn)Target接口,這里是實現(xiàn)了ConsoleRender接口
func(t*TableRender)Render()string{
//關鍵點4:在Target接口實現(xiàn)中,調用Adaptee的原有方法實現(xiàn)具體的業(yè)務邏輯
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()
}

//這里是另一個Adapter,實現(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{
//關鍵點5:在需要Target接口的地方,傳入適配器Adapter實例,其中創(chuàng)建Adapter實例時需要傳入Adaptee實例
c.Output(NewTableRender(result))
}else{
c.Output(NewErrorRender(err))
}
fmt.Println(">pleaseenterasqlexpression:")
fmt.Print(">")
}
}

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

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

擴展

適配器模式在 Gin 中的運用

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

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

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

在實際運用場景中,可能存在這種情況。用戶起初的 Web 框架使用了 Go 原生的net/http,使用場景如下:

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

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

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

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

使用方法如下:

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

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

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

典型應用場景

  • 將一個接口 A 轉換成用戶希望的另外一個接口 B,這樣就能使原來不兼容的接口 A 和接口 B 相互協(xié)作。
  • 老系統(tǒng)的重構。在不改變原有接口的情況下,讓老接口適配到新的接口。

優(yōu)缺點

優(yōu)點

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

缺點

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

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

適配器模式 和裝飾者模式、代理模式在 UML 結構上具有一定的相似性。但適配器模式改變原有對象的接口,但不改變原有功能;而裝飾者模式和代理模式則在不改變接口的情況下,增強原有對象的功能。

文章配圖

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


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

    關注

    7

    文章

    2788

    瀏覽量

    50430
  • 適配器
    +關注

    關注

    9

    文章

    2054

    瀏覽量

    69756
  • 數(shù)據(jù)庫

    關注

    7

    文章

    3927

    瀏覽量

    66272

原文標題:【Go實現(xiàn)】實踐GoF的23種設計模式:適配器模式

文章出處:【微信號:yuanrunzi,微信公眾號:元閏子的邀請】歡迎添加關注!文章轉載請注明出處。

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

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

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

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

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

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

    適配器模式的作用

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

    缺省適配器模式基本概念

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

    對象適配器模式基本概念

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

    什么是硬件適配器模式

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

    適配器模式的本質及分類

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

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

    適配器模式、裝飾器模式、代理模式都屬于設計模式中的結構型模式,結構型設計
    發(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ū)別

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

    java適配器模式實例

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

    JavaScript設計模式適配器模式

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

    大話設計模式之愛你一萬年:第六章 結構型模式適配器模式:i7愛妻:為愛找份工作:3.適配器模式之對象適配器

    在這一節(jié)我們就看一看第一類:對象適配器模式一、對象適配器模式基本概念1.1 說明對象適配器模式
    發(fā)表于 11-06 19:51 ?12次下載
    大話設計<b class='flag-5'>模式</b>之愛你一萬年:第六章 結構型<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>之對象<b class='flag-5'>適配器</b>

    設計模式-適配器模式-以電壓適配器為例

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

    設計模式中什么是適配器模式?

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

    實踐GoF23設計模式:解釋器模式

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