精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

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

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

3天內不再提示

為什么要設計模式

馬哥Linux運維 ? 來源:云原生CTO ? 作者:charts ? 2022-06-14 11:08 ? 次閱讀

GoRustPythonIstiocontainerdCoreDNSEnvoyetcdFluentdHarborHelmJaegerKubernetesOpenPolicyAgentPrometheusRookTiKVTUFVitessArgoBuildpacksCloudEventsCNIContourCortexCRI-OFalcoFluxgRPCKubeEdgeLinkerdNATSNotaryOpenTracingOperatorFrameworkSPIFFESPIREThanos


Go 中的構建器模式

Operator 條件更新上應用 Go 風格的構建器模式的實際示例

建議我們在某個“框架”內進行編碼,即遵循一定的設計模式,這些模式是有效的、可復制的、被廣泛認可的、更容易理解和應用的。

為什么要設計模式

為了不那么抽象,我們從實踐中的一個例子開始。

通常,我們定義一個struct,然后在使用它時對其進行初始化。

typeAstruct{
namestring
}
a:=A{name:“abc”}

這是常見的用法,但不適用于A復雜的場景

  • 多層嵌套字段
  • 超過 5 個字段
  • 不同的字段需要不同的默認值
  • 多個可選字段
  • 以上四種的組合

例如在Kubernetes operator開發中,我們調用SetStatusAndCondition來更新資源信息,其中不僅包含了metav1的基本信息。條件,如狀態,原因,觀察生成等,但也傳遞回調函數,如OnSuccessOnError。圍繞ConditionAndStatus,我們可以添加其他邏輯,比如發送事件、處理不同狀態(成功或失敗)的邏輯,等等,然后定義一個類似如下的結構。

typeConditionAndStatusstruct{
Conditionmetav1.Condition
EventTypestring//eventtype
Recorderrecord.EventRecorder,//K8seventsrecorder
Forcebool,//isForceupdate
OnErrorfunc,//errhandler
OnSuccesfunc,//successhandler
}

它可以通過通過new初始化這個ConditionAndStatus來工作,但是當有超過5個字段并且其中兩個是嵌套的時候,它是累贅和復雜的,這是對非調用者友好的,并且在代碼可讀性上很差。除非conditioneventRecorder被實例化,否則調用者不能實例化ConditionAndStatus。調用者需要知道所有的實現細節,例如,他們應該知道在錯誤處理中更新條件時傳遞onSucc方法,即使只有nil。此外,不同的用戶在不同的地方執行初始化時,每次都需要傳入相同的onSucconErr

那么我們該如何優化這段代碼呢?

Factory 模式

應用Factory模式可能是我們想到的第一個想法,但它不適用于這種情況。

5e4ce432-eb1e-11ec-ba43-dac502259ad0.png

通過Factory模式封裝一些創建方法。

//Createnofalse,nodefaulthandlers
func(cConditionAndStatus)Create(condmetav1.Condition,eventTypestring,recorderrecord.EventRecorder)ConditionAndStatus{
returncreate(cond,eventType,recorder,false,nil,nil)
}

//Createnodefaulthandlers
func(cConditionAndStatus)Create(condmetav1.Condition,eventTypestring,recorderrecord.EventRecorder,forcebool)ConditionAndStatus{
returncreate(cond,eventType,recorder,force,nil,nil)
}

//...morecreatefunctions

func(cConditionAndStatus)Create(condmetav1.Condition,eventTypestring,recorderrecord.EventRecorder,forcebool,onErrfunc,onSuccfunc)ConditionAndStatus{
returnConditionAndStatus{
condtion:cond,
eventType:eventType,
recorder:recorder,
force:force,
onErr:onErr,
onSucces:onSucc,
}
}

api應該易于使用且不易誤用——來自Josh Bloch

然而,Factory模式實現的api并不是那么方便。

顯然,create不是一個選項,因為它需要提供所有參數,傳入的參數越多,操作就越困難。此外,當多個參數為同一類型時,很容易出錯。

盡管其他Factory方法可以通過提供一些默認值來減少傳入的參數來降低復雜性,但它們仍然缺乏靈活性。添加參數后,需要修改所有create *方法。

Builder模式

Builder模式是一種設計模式,旨在為面向對象編程中的各種對象創建問題提供靈活的解決方案

來自https://en.wikipedia.org/wiki/Builder_pattern。

構建器模式為靈活簡化復雜對象的創建鋪平了道路,同時也隱藏了嵌入式類型的一些初始化細節,大大提高了可讀性。

Builder接口

builder接口是兩種builder模式實現之一,buildxxx用接口實現各個字段的方法,Builder通過多態性確定具體的builder。請參閱下面的 UML 流程圖。

5e5c6420-eb1e-11ec-ba43-dac502259ad0.png

讓我們“翻新”以前的ConditionAndStatus.

typeConditionAndStatusBuilderinterface{
SetCondtion(condmetav1.Condition)ConditionAndStatusBuilder
SetEventType(evnetTypestring)ConditionAndStatusBuilder
SetRecorder(recorderrecord.EventRecorder)ConditionAndStatusBuilder
SetForce(forcebool)ConditionAndStatusBuilder
SetOnErr(onErrfunc())ConditionAndStatusBuilder
SetOnSuccess(onSuccfunc())ConditionAndStatusBuilder
Build()ConditionAndStatus
}

typeDefaultBuilderstruct{
conditionmetav1.Condition
eventTypestring//eventtype
recorderrecord.EventRecorder,//K8seventsrecorder
forcebool,//isForceupdate
onErrorfunc,//errhandler
onSuccesfunc,//successhandler
}

func(b*DefaultBuilder)SetCondtion(condmetav1.Condition)DefaultBuilder{
b.condition=cond
returnb
}
//...moresetfuncs

func(b*DefaultBuilder)Build()ConditionAndStatus{
//setsomedefaultvalues
b.force=true
returnConditionAndStatus{
condition:b.condtion,
//...
}
}

要創建ConditionAndStatus,您可以使用注冊方法組成所有構建器,然后通過getByName獲得特定的構建器。

不難得出結論,該模式與Factory模式非常相似,因為每個構建器仍然需要創建所有字段或提供默認值。但它確實向前邁出了一步。

  • 當字段確定時,它可以靈活地添加新的生成器,而不需要修改舊的生成器。
  • 它可以控制創建不同字段的順序。如果字段是相互依賴的,它可以隱藏細節并防止調用者犯錯誤。

然而,它與Factory模式有相同的缺點:一旦添加了字段(在Builder接口中添加方法),就需要修改所有構建器。

Pipeline建設者

另一種構建器模式是管道構建器,它更常見。通過上面的接口builder,你會發現多builder的設計是多余的,而讓調用者控制相關字段的分配更合理:唯一的一個builder管理所有字段初始化,并通過返回builder本身來構建管道在每一步中,最后都組裝成我們想要的。

5e8f8990-eb1e-11ec-ba43-dac502259ad0.png

通用調用代碼的格式為obj.Withxxx().Withyyy().Withzzz().build(). 更改ConditionAndStatus如下。

typeBuilderstruct{
conditionmetav1.Condition
eventTypestring//eventtype
recorderrecord.EventRecorder,//K8seventsrecorder
forcebool,//isForceupdate
onErrorfunc,//errhandler
onSuccesfunc,//successhandler
}

func(b*Builder)WithCondition(condmetav1.Condition)Builder{
b.condition=cond
returnb
}
//...moreWithxxxfuncs

func(b*Builder)Build()ConditionAndStatus{
//setsomedefaultvalues
b.force=true
returnConditionAndStatus{
condition:b.condtion,
//...
}
}

Pipeline builder巧妙地避免了添加新字段帶來的麻煩。只有一個builder,它可以通過添加With*方法輕松處理字段添加。

它對現有的調用者絕對更友好。如果參數是可選的,則不需要修改其他調用者的代碼。而你只有通過添加新的調用者并With*在調用時插入方法來完成它;但是,當需要新參數而沒有默認值時,則需要修改所有調用者的代碼。

當然,沒有一種模式是沒有缺陷的,管道構建器也不是。

  • Withxxx()一旦要構建許多字段,堆積的方法會給調用者帶來麻煩并降低可讀性。
  • 無法控制字段的初始化順序。如果存在依賴關系,則需要出色的錯誤控制和文檔來避免錯誤。
  • 代碼不是 Go 風格,而是更多 Java 風格。

可選的構建器模式

如果我們進一步優化管道構建器會怎樣?正如Dave Cheney在他的Practical Go中提到的那樣,我們應該以更多 Go 的方式嘗試它。

首選 var args[]T 參數

深入挖掘,我們看到這里的大部分字段都是可選的,并且可以var args自然地定義。如有傳入,申報;如果沒有,請忽略它。因此,builder/factory當隱藏實現細節時,只需要一種方法來處理整個對象的創建。

讓我們一步一步地把這個想法付諸實踐。

將可選字段抽象到構建結構中,而不是將所有字段都放入。要將ConditionAndStatus轉換為以下結構,其中配置包含所有可選字段。

typeConditionAndStatusstruct{
conditionmetav1.Condition
eventTypestring//eventtype
recorderrecord.EventRecorder,//K8seventsrecorder
configsconfigs//Optionalconfigs
}

typeconfigsstruct{
forcebool,//isForceupdate
onErrorfunc,//errhandler
onSuccesfunc,//successhandler
}

對于配置,使用func選項接受一個*configs并返回自身以集成到管道中。需要使用以下方法。

typeconfigsstruct{
forcebool,//isForceupdate
onErrorfunc,//errhandler
onSuccesfunc,//successhandler
}

typeOptionfunc(*configs)

funcForceUpdate(forcebool)Option{returnfunc(c*configs){c.force=force}}

funcOnErr(onErrfunc())Option{returnfunc(c*configs){c.onErr=onErr}}

funcOnSuccess(onSuccfunc())Option{returnfunc(c*configs){c.onSuccess=onSucc}}

然后是新的create方法,包括必要字段和可選配置的初始化。因為所有可選的配置都是用func類型的返回值初始化的,所以整個配置的賦值只能用一個循環來完成。超級簡潔!

funcCreate(conditionmetav1.Condition,eventTypestring,recorderrecord.EventRecorder,os...Option)error{
opts:=configs{
force:false,
onSuccess:func(){},
onError:nil,
}
//Applyalltheoptionalconfigs
for_,applyOption:=rangeos{
applyOption(&opts)
}
//checkrequiredfields

//updateconditionshere

//handleerr
ifopts.err!=nil{
returnopts.onError()
}

//eveutallycallsuccessfunc
opts.onSuccess()
}

調用方可以根據場景選擇可選配置,避免誤用。

setCondition(
metav1.Condition{
Type:apis.Ready,
Status:metav1.ConditionFalse,
Reason:apis.UpstreamUnavailable,
Message:fmt.Sprintf("Failedtosetresources%#v",resource),
},
"Update",
nil,
//onlyneedonErrfuncfromtheoptionalconfigs.
conditionAndStatus.ForOnErr(err),
)

Builder in Kubernetes

Kubernetes源代碼的幾乎每個角落都可以看到這種go風格的代碼。幾乎所有的結構被*配置是建立在可選的建造者模式,如PodApplyConfiguration EventApplyConfiguration和配置文檔你找到包裹。這些逐層嵌套配置獲得最終值與一個或多個方法類似于PodApplyConfiguration提取。

最后

設計模式是經典的,盡管不是所有的模式都能在Go中完美實現。Builder無疑是其中最杰出的一個,我們應該最大限度地利用Optional管道生成器模式來構建一些配置對象,特別是在設計公共模塊時。使用靈活、遵守代碼標準和擴展友好的api,可以大大減輕升級壓力。

感謝你的閱讀!

原文標題:Go 中的構建器模式

文章出處:【微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 源代碼
    +關注

    關注

    96

    文章

    2944

    瀏覽量

    66673
  • 設計模式
    +關注

    關注

    0

    文章

    53

    瀏覽量

    8623
  • Struct
    +關注

    關注

    0

    文章

    31

    瀏覽量

    10859
  • 云原生
    +關注

    關注

    0

    文章

    242

    瀏覽量

    7939

原文標題:Go 中的構建器模式

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    為什么官方的移植DEMO下載到FLASH?STlink仿真模式問題?

    我最近在做STM32F107移植uCOSii,遇到幾個問題,為什么官方的移植DEMO下載到FLASH?在用STlink仿真時,使用JATG模式出現錯誤,而使用SWD就正常運行呢?備注:編譯器
    發表于 03-27 15:04

    請問4通道都用DMA模式怎么使用

    我有4個AD要用到,想用DMA模式,看庫函數例程只有一個通道,請問4通道都用DMA模式怎么使用
    發表于 09-26 09:23

    在DCM下的ip要比CCM模式下的ip大出不少

    在DCM下的ip要比CCM模式下的ip大出不少的,同等條件下CCM模式有效值電流更低。有沒有詳細的推導公式假設輸出功率相同,開關頻率相同,同樣的輸入電壓
    發表于 10-23 11:01

    CAN初始化,CAN實驗初始化,CAN_DeInit()這句話不寫可以嗎

    一些實驗,加了缺省設置,然后自己又配置了。感覺沒必要,CAN實驗初始化,CAN_DeInit()這句話不寫也行把但很多實驗都這樣寫,有什么好處?缺省設置不一定是你模式
    發表于 05-31 04:35

    STM32 IO口設置成什么模式

    stm32的部分管腳可以兼容5V,那么請問當外接信號為5V作為輸入時,IO口設置成什么模式
    發表于 05-29 10:13

    為什么DAC端口設置為模擬輸入模式

    的 DAC 通道 1 在 PA4 上,所以,我們先要使能 PORTA 的時鐘,然后設置 PA4 為模擬輸入。DAC 本身是輸出,但是為什么端口設置為模擬輸入模式呢?因為一但使能 DACx 通道之后
    發表于 08-17 07:22

    什么是設計模式?為什么學習設計模式

    物是人非事事休,當周圍的一切都發生著改變,包括我們的需求、程序等,我們又該如何去應對和解決呢?歡迎進入編程人員必經之路------設計模式1 本篇概述什么是設計模式為什么學習設計模式
    發表于 01-19 06:41

    CH9141默認的應該是從機模式,是設置成主機模式才能連接嗎?

    CH9141默認的應該是從機模式,是設置成主機模式才能連接嗎?
    發表于 09-21 07:33

    ESP32從AP切換到STA模式重啟么?

    ESP32上電先跑STA模式,接收到指令后切換AP模式進入UDP服務接收SSID PASSWORD,寫入NVS后再切回STA模式連接AP失敗怎么搞?STA模式下都是從NVS讀取
    發表于 03-09 06:22

    性能模式和省電模式的區別是什么

    大家都知道,Long long agoEMUI就有了不同的應用模式,是為了兼顧不同的使用場景而為用戶設置的,例如玩游戲時需要性能強,就需要性能模式,出差在外時,盡量續航長,就選擇省電模式
    發表于 07-13 08:47 ?1w次閱讀

    什么是框架?MATLAB的單元測試框架中文版資料詳細概述

    從邏輯上來說,框架 (Framework),是?個??向對象和設計模式更加復雜的結構,但讀者不?擔?,雖然框架在結構上?模式復雜,但是學習起來?設計
    發表于 11-18 08:00 ?0次下載
    什么是框架?MATLAB的單元測試框架中文版資料詳細概述

    手機雙屏模式如何設置

    最近小編發現有諸多的小伙伴們對于手機雙屏模式如何設置都頗為感興趣的,大家也都想要及時了解到手機雙屏模式如何設置相關信息
    的頭像 發表于 04-22 10:30 ?4.3w次閱讀

    三星顯示器調模式怎么調?

    通過顯示器的MENU按鍵,調出顯示器調節菜單,通過顯示器自帶的方向按鍵,調整光標到【圖像】-【靈巧模式】中,選擇需要的顯示模式即可。
    的頭像 發表于 04-22 10:51 ?2.7w次閱讀

    為什么串口喚醒STOP模式?如何才能實現串口喚醒STOP模式呢?

    STM32常見的低功耗模式有三種:睡眠模式、STOP模式以及待機模式,STM32L系列還有其他低功耗模式
    的頭像 發表于 06-06 11:02 ?4203次閱讀
    為什么<b class='flag-5'>要</b>串口喚醒STOP<b class='flag-5'>模式</b>?如何才能實現串口喚醒STOP<b class='flag-5'>模式</b>呢?

    什么是定長控制功能?變頻器如何設置定長控制模式

    什么是定長控制功能?變頻器如何設置定長控制模式?變頻器定長模式的控制設置是如何工作的? 定長控制功能是變頻器控制系統中的一種模式,其主要作用是控制控制中所需軸的行程長度,從而實現工作
    的頭像 發表于 10-22 14:38 ?1603次閱讀