日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

一些实用的编程模式 | Options模式

發(fā)布時(shí)間:2024/4/11 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一些实用的编程模式 | Options模式 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

今天開個(gè)新系列,講一些實(shí)用的編程模式,每個(gè)編程模式學(xué)完后,都能馬上在實(shí)戰(zhàn)中應(yīng)用起來(lái),讓我們寫出更富表達(dá)力、易維護(hù)、好擴(kuò)展、優(yōu)雅億點(diǎn)點(diǎn)的代碼。

這些編程模式的示例我會(huì)用Go來(lái)演示,但其實(shí)這些模式大多與語(yǔ)言無(wú)關(guān),無(wú)論你平時(shí)主攻Go、Java還是JavaScript 我覺得都能用上。

為避免貼長(zhǎng)篇代碼,我會(huì)適當(dāng)用一些偽代碼,大家理解思路后,可以在我的GitHub倉(cāng)庫(kù)gocookbook找到完整可運(yùn)行的代碼。

公眾號(hào)回復(fù) gocookbook?關(guān)鍵字獲取鏈接,打開后Ctrl+F搜"Options"

系列第一篇要分享的編程模式是函數(shù)式編程里的Options模式

Options模式解決什么問(wèn)題

Options模式可以讓具有多個(gè)可選參數(shù)的函數(shù)或者方法更整潔和好擴(kuò)展,當(dāng)一個(gè)函數(shù)具有五六個(gè)甚至十個(gè)以上的可選參數(shù)時(shí)使用這種模式的優(yōu)勢(shì)會(huì)體現(xiàn)的很明顯,我們還是通過(guò)一些例子慢慢感受一下。

比如我們要在項(xiàng)目里封裝一個(gè)通用的發(fā)Http請(qǐng)求的工具函數(shù),它的參數(shù)可能會(huì)有哪些呢?因?yàn)槭枪ぞ吆瘮?shù),要做到通用就必然需要定義很多能配置HTTP客戶端的參數(shù),比如:

func?HttpRequest(method?string,?url?string,?body?[]byte,?headers?map[string]string,?timeout?time.Duration)?...

函數(shù)簽名里的返回值這里就省略了,太寬影響閱讀,這里大家注意一下。

上面這個(gè)工具函數(shù),如果只是做GET請(qǐng)求的話,很多HTTP客戶端的設(shè)置是不需要設(shè)置的,而且超時(shí)時(shí)間我們一般都會(huì)設(shè)置一個(gè)默認(rèn)的。如果還按普通定義函數(shù)的方法來(lái)實(shí)現(xiàn)的話,函數(shù)邏輯里勢(shì)必會(huì)有不少判斷空值的邏輯。

if?body?!=?nil?{//?設(shè)置請(qǐng)求體Data...... }if?headers?!=?nil?{//?設(shè)置請(qǐng)求頭...... }

調(diào)用的時(shí)候,調(diào)用者的代碼也不得不傳一些零值給不需要自定義的配置參數(shù)。

HttpRequest('GET',?'https://www.baidu.com',?nil,?nil,?2?*?time.Second)

如果是Java的話,其實(shí)是可以通過(guò)方法的重載解決這個(gè)問(wèn)題,但是如果可選的參數(shù)是十幾個(gè),各個(gè)調(diào)用方對(duì)可選參數(shù)的順序要求不一樣的話,定義這個(gè)多重載方法顯然不是一個(gè)好的解決方案。

另外一種常用的解決方案是,工具函數(shù)的簽名定義時(shí),不再定義各個(gè)可能需要配置的可選參數(shù),轉(zhuǎn)而定義一個(gè)配置對(duì)象。

type?HttpClientConfig?struct?{timeout?time.Durationheaders?map[string]stringbody????[]byte }func?HttpRequest(method?string,?url?string,?config?*HttpClientConfig)?...

配置對(duì)象方案的問(wèn)題

函數(shù)簽名里通過(guò)傳遞一個(gè)配置對(duì)象來(lái)聚合各種可能的可選參數(shù)這個(gè)方案,對(duì)調(diào)用者來(lái)說(shuō),比上一種方法看起來(lái)簡(jiǎn)潔了不少,如果全都是默認(rèn)選項(xiàng)只需要給配置對(duì)象這個(gè)參數(shù)傳遞一個(gè)零值即可。

HttpRequest('GET',?'https://www.baidu.com',?nil)

但是對(duì)于函數(shù)的實(shí)現(xiàn)方來(lái)說(shuō),仍然少不了那些選項(xiàng)參數(shù)非零值的判斷,而且因?yàn)榕渲脤?duì)象在函數(shù)外部可以改變,這就有一定幾率配置對(duì)象在函數(shù)內(nèi)部未被使用前被外部程序改變,真正發(fā)生了相關(guān)的BUG,排查起來(lái)會(huì)比較頭疼。

可變參數(shù)方案的問(wèn)題

與配置對(duì)象方案類似,如果單純通過(guò)可變參數(shù)來(lái)解決這個(gè)問(wèn)題,也會(huì)有不少問(wèn)題

func?HttpRequest(method?string,?url?string,?options?...interface{})?...

雖然參數(shù)是可變的,但是實(shí)現(xiàn)方需要通過(guò)遍歷設(shè)置HTTP客戶端的不同選項(xiàng),這就讓可變參數(shù)固定了傳遞順序,調(diào)用方如果想要設(shè)置某個(gè)可選項(xiàng)還得記住參數(shù)順序,切無(wú)法直接通過(guò)函數(shù)簽名就確定參數(shù)順序,貌似還不如咱們最原始的解決方案。

使用Options模式的方案

最后,我們來(lái)說(shuō)一下使用Options模式怎么解決這個(gè)問(wèn)題,其實(shí)如果你如果使用過(guò)gRPC的話,會(huì)發(fā)現(xiàn)gRPC的SDK里Options模式出現(xiàn)的幾率相當(dāng)高,比如它的客戶端方法可以傳遞不少以with開頭的閉包函數(shù)方法.

client.cc,?err?=?grpc.Dial("127.0.0.1:12305",grpc.WithInsecure(),grpc.WithUnaryInterceptor(...),grpc.WithStreamInterceptor(...),grpc.WithAuthority(...) )

這些配置方法返回的都是一個(gè)名為DialOption的interface

type?DialOption?interface?{apply(*dialOptions) }func?WithInsecure()?DialOption?{... }

現(xiàn)在我們就使用Options模式對(duì)我們的工具函數(shù)進(jìn)行一下改造,首先定義一個(gè)契約和配置對(duì)象。

//?針對(duì)可選的HTTP請(qǐng)求配置項(xiàng),模仿gRPC使用的Options設(shè)計(jì)模式實(shí)現(xiàn) type?requestOption?struct?{timeout?time.Durationdata????stringheaders?map[string]string }type?Option?struct?{apply?func(option?*requestOption) }func?defaultRequestOptions()?*requestOption?{return?&requestOption{?//?默認(rèn)請(qǐng)求選項(xiàng)timeout:?5?*?time.Second,data:????"",headers:?nil,} }

接下來(lái)我們要定義的配置函數(shù),每個(gè)都會(huì)設(shè)置請(qǐng)求配置對(duì)象里的某一個(gè)配置

func?WithTimeout(timeout?time.Duration)?*Option?{return?&Option{apply:?func(option?*requestOption)?{option.timeout?=?timeout},} }func?WithData(data?string)?*Option?{return?&Option{apply:?func(option?*requestOption)?{option.data?=?data},} }

那么此時(shí)我們的工具函數(shù)的簽名就應(yīng)用上上面定義的接口契約

func?HttpRequest(method?string,?url?string,?options?...*Option)?...

在其實(shí)現(xiàn)里我們只需要遍歷options這個(gè)可變參數(shù),調(diào)用每個(gè)Option對(duì)象的apply方法對(duì)配置對(duì)象進(jìn)行配置即可,不用在擔(dān)心可變參數(shù)的順序。

func?httpRequest(method?string,?url?string,?options?...*Option)?{reqOpts?:=?defaultRequestOptions()?//?默認(rèn)的請(qǐng)求選項(xiàng)for?_,?opt?:=?range?options?{??????//?在reqOpts上應(yīng)用通過(guò)options設(shè)置的選項(xiàng)opt.apply(reqOpts)}//?創(chuàng)建請(qǐng)求對(duì)象req,?err?:=?http.NewRequest(method,?url,?strings.NewReader(reqOpts.data))//?設(shè)置請(qǐng)求頭for?key,?value?:=?range?reqOpts.headers?{req.Header.Add(key,?value)}//?發(fā)起請(qǐng)求......return }

總結(jié)

最后我們的HTTP工具函數(shù)的調(diào)用方式就變成了,下面這種更靈活更富表達(dá)力的方式。

HttpRequest("GET",?url)HttpRequest("POST",?url,?WithHeaders(headers)HttpRequest("POST",?url,?WithTimeout(timeout),?WithHeaders(headers),?WithData(data))

從實(shí)現(xiàn)方來(lái)看呢?如果后面要給配置對(duì)象里增加其他配置項(xiàng),只需要擴(kuò)充類型的字段,在定義一個(gè)對(duì)應(yīng)的With方法即可,擴(kuò)展性完全在可接受范圍內(nèi)。

好了Options模式你學(xué)會(huì)沒,想不想趕快用起來(lái),現(xiàn)在公眾號(hào)里回復(fù)關(guān)鍵字? gocookbook? 就能獲得完整可運(yùn)行的代碼示例打開鏈接后記得Ctrl+F搜"Options")。下次再遇到類似的場(chǎng)景后記得把今天學(xué)到的用上呀。

給網(wǎng)管個(gè)星標(biāo),第一時(shí)間吸我的知識(shí)?👆

總結(jié)

以上是生活随笔為你收集整理的一些实用的编程模式 | Options模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。