欧美性猛交xxxx免费看_牛牛在线视频国产免费_天堂草原电视剧在线观看免费_国产粉嫩高清在线观看_国产欧美日本亚洲精品一5区

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

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

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

GoF設計模式之訪問者模式

元閏子的邀請 ? 來源:元閏子的邀請 ? 作者:元閏子的邀請 ? 2022-10-08 11:05 ? 次閱讀

上一篇:【Go實現(xiàn)】實踐GoF的23種設計模式:迭代器模式

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

簡介

GoF 對訪問者模式Visitor Pattern)的定義如下:

Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

訪問者模式的目的是,解耦數(shù)據(jù)結(jié)構(gòu)和算法,使得系統(tǒng)能夠在不改變現(xiàn)有代碼結(jié)構(gòu)的基礎上,為對象新增一種新的操作。

上一篇介紹的迭代器模式也做到了數(shù)據(jù)結(jié)構(gòu)和算法的解耦,不過它專注于遍歷算法。訪問者模式,則在遍歷的同時,將操作作用到數(shù)據(jù)結(jié)構(gòu)上,一個常見的應用場景是語法樹的解析。

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

c3487bdc-4571-11ed-96c9-dac502259ad0.jpg

場景上下文

在簡單的分布式應用系統(tǒng)(示例代碼工程)中,db 模塊用來存儲服務注冊和監(jiān)控信息,它是一個 key-value 數(shù)據(jù)庫。另外,我們給 db 模塊抽象出Table對象:

//demo/db/table.go
packagedb

//Table數(shù)據(jù)表定義
typeTablestruct{
namestring
metadatamap[string]int//key為屬性名,value屬性值的索引,對應到record上存儲
recordsmap[interface{}]record
iteratorFactoryTableIteratorFactory//默認使用隨機迭代器
}

目的是提供類似于關系型數(shù)據(jù)庫的按列查詢能力,比如:

c399aa70-4571-11ed-96c9-dac502259ad0.jpg

上述的按列查詢只是等值比較,未來還可能會實現(xiàn)正則表達式匹配等方式,因此我們需要設計出可供未來擴展的接口。這種場景,使用訪問者模式正合適。

代碼實現(xiàn)

//demo/db/table_visitor.go
packagedb

//關鍵點1:定義表查詢的訪問者抽象接口,允許后續(xù)擴展查詢方式
typeTableVisitorinterface{
//關鍵點2:Visit方法以Element作為入?yún)?,這里的Element為Table對象
Visit(table*Table)([]interface{},error)
}

//關鍵點3:定義Visitor抽象接口的實現(xiàn)對象,這里FieldEqVisitor實現(xiàn)按列等值查詢邏輯
typeFieldEqVisitorstruct{
fieldstring
valueinterface{}
}

//關鍵點4:為FieldEqVisitor定義Visit方法,實現(xiàn)具體的等值查詢邏輯
func(f*FieldEqVisitor)Visit(table*Table)([]interface{},error){
result:=make([]interface{},0)
idx,ok:=table.metadata[f.field]
if!ok{
returnnil,ErrRecordNotFound
}
for_,r:=rangetable.records{
ifreflect.DeepEqual(r.values[idx],f.value){
result=append(result,r)
}
}
iflen(result)==0{
returnnil,ErrRecordNotFound
}
returnresult,nil
}

funcNewFieldEqVisitor(fieldstring,valueinterface{})*FieldEqVisitor{
return&FieldEqVisitor{
field:field,
value:value,
}
}

//demo/db/table.go
packagedb

typeTablestruct{...}
//關鍵點5:為Element定義Accept方法,入?yún)閂isitor接口
func(t*Table)Accept(visitorTableVisitor)([]interface{},error){
returnvisitor.Visit(t)
}

客戶端可以這么使用:

funcclient(){
table:=NewTable("testRegion").WithType(reflect.TypeOf(new(testRegion)))
table.Insert(1,&testRegion{Id:1,Name:"beijing"})
table.Insert(2,&testRegion{Id:2,Name:"beijing"})
table.Insert(3,&testRegion{Id:3,Name:"guangdong"})

visitor:=NewFieldEqVisitor("name","beijing")
result,err:=table.Accept(visitor)
iferr!=nil{
t.Error(err)
}
iflen(result)!=2{
t.Errorf("visitfailed,want2,got%d",len(result))
}
}

總結(jié)實現(xiàn)訪問者模式的幾個關鍵點:

定義訪問者抽象接口,上述例子為TableVisitor, 目的是允許后續(xù)擴展表查詢方式。

訪問者抽象接口中,Visit方法以 Element 作為入?yún)?,上述例子中?Element 為Table對象。

為 Visitor 抽象接口定義具體的實現(xiàn)對象,上述例子為FieldEqVisitor。

在訪問者的Visit方法中實現(xiàn)具體的業(yè)務邏輯,上述例子中FieldEqVisitor.Visit(...)實現(xiàn)了按列等值查詢邏輯。

在被訪問者 Element 中定義 Accept 方法,以訪問者 Visitor 作為入?yún)?。上述例子中為Table.Accept(...)方法。

擴展

Go 風格實現(xiàn)

上述實現(xiàn)是典型的面向?qū)ο箫L格,下面以 Go 風格重新實現(xiàn)訪問者模式:

//demo/db/table_visitor_func.go
packagedb

//關鍵點1:定義一個訪問者函數(shù)類型
typeTableVisitorFuncfunc(table*Table)([]interface{},error)

//關鍵點2:定義工廠方法,工廠方法返回的是一個訪問者函數(shù),實現(xiàn)了具體的訪問邏輯
funcNewFieldEqVisitorFunc(fieldstring,valueinterface{})TableVisitorFunc{
returnfunc(table*Table)([]interface{},error){
result:=make([]interface{},0)
idx,ok:=table.metadata[field]
if!ok{
returnnil,ErrRecordNotFound
}
for_,r:=rangetable.records{
ifreflect.DeepEqual(r.values[idx],value){
result=append(result,r)
}
}
iflen(result)==0{
returnnil,ErrRecordNotFound
}
returnresult,nil
}
}

//關鍵點3:為Element定義Accept方法,入?yún)閂isitor函數(shù)類型
func(t*Table)AcceptFunc(visitorFuncTableVisitorFunc)([]interface{},error){
returnvisitorFunc(t)
}

客戶端可以這么使用:

funcclient(){
table:=NewTable("testRegion").WithType(reflect.TypeOf(new(testRegion)))
table.Insert(1,&testRegion{Id:1,Name:"beijing"})
table.Insert(2,&testRegion{Id:2,Name:"beijing"})
table.Insert(3,&testRegion{Id:3,Name:"guangdong"})

result,err:=table.AcceptFunc(NewFieldEqVisitorFunc("name","beijing"))
iferr!=nil{
t.Error(err)
}
iflen(result)!=2{
t.Errorf("visitfailed,want2,got%d",len(result))
}
}

Go 風格的實現(xiàn),利用了函數(shù)閉包的特點,更加簡潔了。

總結(jié)幾個實現(xiàn)關鍵點:

定義一個訪問者函數(shù)類型,函數(shù)簽名以 Element 作為入?yún)?,上述例子為TableVisitorFunc類型。

定義一個工廠方法,工廠方法返回的是具體的訪問訪問者函數(shù),上述例子為NewFieldEqVisitorFunc方法。這里利用了函數(shù)閉包的特性,在訪問者函數(shù)中直接引用工廠方法的入?yún)ⅲcFieldEqVisitor中持有兩個成員屬性的效果一樣。

為 Element 定義 Accept 方法,入?yún)?Visitor 函數(shù)類型 ,上述例子是Table.AcceptFunc(...)方法。

與迭代器模式結(jié)合

訪問者模式經(jīng)常與迭代器模式一起使用。比如上述例子中,如果你定義的 Visitor 實現(xiàn)不在 db 包內(nèi),那么就無法直接訪問Table的數(shù)據(jù),這時就需要通過Table提供的迭代器來實現(xiàn)。

在簡單的分布式應用系統(tǒng)(示例代碼工程)中,db 模塊存儲的服務注冊信息如下:

//demo/service/registry/model/service_profile.go
packagemodel

//ServiceProfileRecord存儲在數(shù)據(jù)庫里的類型
typeServiceProfileRecordstruct{
Idstring//服務ID
TypeServiceType//服務類型
StatusServiceStatus//服務狀態(tài)
Ipstring//服務IP
Portint//服務端口
RegionIdstring//服務所屬regionId
Priorityint//服務優(yōu)先級,范圍0~100,值越低,優(yōu)先級越高
Loadint//服務負載,負載越高表示服務處理的業(yè)務壓力越大
}

現(xiàn)在,我們要查詢符合指定ServiceId和ServiceType的服務記錄,可以這么實現(xiàn)一個 Visitor:

//demo/service/registry/model/service_profile.go
packagemodel

typeServiceProfileVisitorstruct{
svcIdstring
svcTypeServiceType
}

func(s*ServiceProfileVisitor)Visit(table*db.Table)([]interface{},error){
varresult[]interface{}
//通過迭代器來遍歷Table的所有數(shù)據(jù)
iter:=table.Iterator()
foriter.HasNext(){
profile:=new(ServiceProfileRecord)
iferr:=iter.Next(profile);err!=nil{
returnnil,err
}
//先匹配ServiceId,如果一致則無須匹配ServiceType
ifprofile.Id!=""&&profile.Id==s.svcId{
result=append(result,profile)
continue
}
//ServiceId匹配不上,再匹配ServiceType
ifprofile.Type!=""&&profile.Type==s.svcType{
result=append(result,profile)
}
}
returnresult,nil
}

典型應用場景

k8s 中,kubectl 通過訪問者模式來處理用戶定義的各類資源。

編譯器中,通常使用訪問者模式來實現(xiàn)對語法樹解析,比如 LLVM。

希望對一個復雜的數(shù)據(jù)結(jié)構(gòu)執(zhí)行某些操作,并支持后續(xù)擴展。

優(yōu)缺點

優(yōu)點

數(shù)據(jù)結(jié)構(gòu)和操作算法解耦,符合單一職責原則。

支持對數(shù)據(jù)結(jié)構(gòu)擴展多種操作,具備較強的可擴展性,符合開閉原則。

缺點

訪問者模式某種程度上,要求數(shù)據(jù)結(jié)構(gòu)必須對外暴露其內(nèi)在實現(xiàn),否則訪問者就無法遍歷其中數(shù)據(jù)(可以結(jié)合迭代器模式來解決該問題)。

如果被訪問對象內(nèi)的數(shù)據(jù)結(jié)構(gòu)變更,可能要更新所有的訪問者實現(xiàn)。

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

訪問者模式 經(jīng)常和迭代器模式一起使用,使得被訪問對象無須向外暴露內(nèi)在數(shù)據(jù)結(jié)構(gòu)。

也經(jīng)常和組合模式一起使用,比如在語法樹解析中,遞歸訪問和解析樹的每個節(jié)點(節(jié)點組合成樹)。

文章配圖

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

審核編輯:湯梓紅

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

    關注

    30

    文章

    4830

    瀏覽量

    69094
  • 設計模式
    +關注

    關注

    0

    文章

    53

    瀏覽量

    8655
  • 迭代器
    +關注

    關注

    0

    文章

    44

    瀏覽量

    4350

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

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

收藏 人收藏

    評論

    相關推薦

    Command模式與動態(tài)語言

    Gof的設計模式中,有一個模式引起的爭議比較大,有很多人甚至認為這個模式應該排除在OO模式之外,原因在于它不具有OO的特性
    發(fā)表于 06-22 10:20 ?1047次閱讀
    Command<b class='flag-5'>模式</b>與動態(tài)語言

    Java設計模式分析觀察

    觀察模式的流程跟報紙訂閱方式一致,即:觀察模式=出版+訂閱,只是名稱不一樣,出版
    發(fā)表于 09-26 17:36 ?0次下載

    在 Java8 環(huán)境下實現(xiàn)觀察模式的實例分析

    觀察(Observer)模式又名發(fā)布-訂閱(Publish/Subscribe)模式,是四人組(GoF,即 Erich Gamma、Richard Helm、Ralph Johnso
    發(fā)表于 10-12 16:09 ?0次下載
    在 Java8 環(huán)境下實現(xiàn)觀察<b class='flag-5'>者</b><b class='flag-5'>模式</b>的實例分析

    Java設計模式(二十一):中介模式

    中介模式(Mediator Pattern) 中介模式(Mediator Pattern): 屬于對象的行為模式。又叫調(diào)停
    發(fā)表于 01-24 11:28 ?320次閱讀

    嵌入式軟件設計設計模式

    文章目錄前言1.設計模式適配器模式2.設計模式單例模式3.設計
    發(fā)表于 10-21 11:07 ?9次下載
    嵌入式軟件設計<b class='flag-5'>之</b>設計<b class='flag-5'>模式</b>

    嵌入式軟件設計模式 好文值得收藏

    本文引用自本人公眾號文章: 嵌入式開發(fā)中的兩點編程思想 ? C語言也很講究設計模式?一文講透 ? 包含如下: 01)C語言和設計模式(繼承、封裝、多態(tài)) ? 02)C語言和設計模式訪問者
    的頭像 發(fā)表于 06-20 09:09 ?2027次閱讀

    GoF給裝飾模式的定義

    的源碼,就會發(fā)現(xiàn) middleware 功能的實現(xiàn)用的就是裝飾模式(Decorator Pattern)。
    的頭像 發(fā)表于 06-29 10:22 ?858次閱讀

    GoF設計模式觀察模式

    現(xiàn)在有 2 個服務,Service A 和 Service B,通過 REST 接口通信;Service A 在某個業(yè)務場景下調(diào)用 Service B 的接口完成一個計算密集型任務,假設接口為 http://service_b/api/v1/domain;該任務運行時間很長,但 Service A 不想一直阻塞在接口調(diào)用上。為了滿足 Service A 的要求,通常有 2 種方案:
    的頭像 發(fā)表于 07-25 11:32 ?1075次閱讀

    GoF設計模式代理模式

    它是一個使用率非常高的設計模式,在現(xiàn)實生活中,也是很常見。比如,演唱會門票黃牛。假設你需要看一場演唱會,但官網(wǎng)上門票已經(jīng)售罄,于是就當天到現(xiàn)場通過黃牛高價買了一張。在這個例子中,黃牛就相當于演唱會門票的代理,在正式渠道無法購買門票的情況下,你通過代理完成了該目標。
    的頭像 發(fā)表于 10-17 09:45 ?980次閱讀

    設計模式訪問者設計模式

    訪問者設計模式是一種行為型設計模式,用于將算法與對象結(jié)構(gòu)分離。它允許你在不改變對象結(jié)構(gòu)的前提下定義新的操作。
    的頭像 發(fā)表于 06-06 11:25 ?890次閱讀

    設計模式行為型:訪問者模式

    訪問者模式(Visitor Pattern)中,我們使用了一個訪問者類,它改變了元素類的執(zhí)行算法。
    的頭像 發(fā)表于 06-07 15:11 ?794次閱讀
    設計<b class='flag-5'>模式</b>行為型:<b class='flag-5'>訪問者</b><b class='flag-5'>模式</b>

    設計模式創(chuàng)造性:建造模式

    建造模式(Builder Pattern)使用多個簡單的對象一步一步構(gòu)建成一個復雜的對象。這種類型的設計模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式。
    的頭像 發(fā)表于 06-09 16:25 ?779次閱讀
    設計<b class='flag-5'>模式</b>創(chuàng)造性:建造<b class='flag-5'>者</b><b class='flag-5'>模式</b>

    UVM設計模式訪問者模式

    Visitor Pattern: 允許一個或者多個操作應用到一組對象上,解耦操作和對象本身。換言之,如果component的數(shù)據(jù)結(jié)構(gòu)是比較穩(wěn)定的,但其是易于變化的,那么使用訪問者模式是個不錯的選擇。
    的頭像 發(fā)表于 08-11 09:28 ?820次閱讀
    UVM設計<b class='flag-5'>模式</b><b class='flag-5'>之</b><b class='flag-5'>訪問者</b><b class='flag-5'>模式</b>

    實踐GoF的23種設計模式:備忘錄模式

    相對于代理模式、工廠模式等設計模式,備忘錄模式(Memento)在我們?nèi)粘i_發(fā)中出鏡率并不高,除了應用場景的限制之外,另一個原因,可能是備忘錄模式
    的頭像 發(fā)表于 11-25 09:05 ?602次閱讀
    實踐<b class='flag-5'>GoF</b>的23種設計<b class='flag-5'>模式</b>:備忘錄<b class='flag-5'>模式</b>

    實踐GoF的23種設計模式:解釋器模式

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