優(yōu)雅寫go:如何用函數(shù)實(shí)現(xiàn)責(zé)任鏈模式躬存?

責(zé)任鏈模式(chain of responsibility)是赫赫有名的GoF書中描述的23個(gè)經(jīng)典模式之一。

這個(gè)模式通過將請(qǐng)求的處理者組織成一個(gè)鏈條孝扛,有效避免請(qǐng)求發(fā)送者與多個(gè)請(qǐng)求處理者耦合在一起。

經(jīng)典實(shí)現(xiàn)

具體到實(shí)現(xiàn)這一塊幽崩,書中和網(wǎng)上提供的內(nèi)容苦始,大部分都是拿Java舉例,即使用其它語言如python慌申,也基本都是面向?qū)ο筮@那一套陌选。

一般都是先給你一個(gè)這樣的圖。

責(zé)任鏈?zhǔn)疽鈭D

然后定義Handler接口和若干個(gè)實(shí)現(xiàn)了接口的Receiver對(duì)象蹄溉。

不滿之處

但是如果你像我一樣咨油,用go語言,『函數(shù)是一等公民』柒爵,卻還在定義結(jié)構(gòu)體和方法役电,就顯得有點(diǎn)笨重了。

不管你們滿不滿意棉胀,反正我是不滿意法瑟。

第一,看起來很臃腫唁奢,不符合go語言極簡設(shè)計(jì)的思想霎挟。
第二,沒有利用好go語言的特性麻掸。

所以酥夭,我用函數(shù)式風(fēng)格重新實(shí)現(xiàn)了一遍。

重新實(shí)現(xiàn)

實(shí)現(xiàn)一個(gè)責(zé)任鏈有幾個(gè)步驟:

  1. 定義統(tǒng)一的Handler接口
  2. 按Handler的定義论笔,實(shí)現(xiàn)不同的Receiver處理類
  3. 將實(shí)現(xiàn)的Receiver組織成鏈?zhǔn)浇Y(jié)構(gòu)
  4. 客戶端訪問其鏈頭

我們以一個(gè)常用的緩存訪問為例采郎,原始數(shù)據(jù)存放于mysql數(shù)據(jù)庫中,使用key-value的形式緩存于redis與本地內(nèi)存memory狂魔。

查詢時(shí)蒜埋,先查本地內(nèi)存memory,如果查不到最楷,則去redis查詢整份,如果redis也沒有,再到mysql數(shù)據(jù)庫中查籽孙。

定義Handler接口

type Handler func(string) (string, bool)

沒錯(cuò)烈评,就是只有一行代碼!很簡潔有木有犯建。

go語言允許函數(shù)有多個(gè)返回值讲冠,我們用第一個(gè)string類型返查到的值,第二個(gè)bool類型返回是否查詢到值适瓦。

實(shí)現(xiàn)Receiver

由于使用函數(shù)風(fēng)格實(shí)現(xiàn)竿开,其實(shí)就是編寫符合Handler的函數(shù)實(shí)現(xiàn)谱仪。

我們需要提供memory, redis否彩,mysql三個(gè)不同的實(shí)現(xiàn)疯攒。

func MemoryGetValue(key string) (string, bool) {
   var value string
   var hasValue bool

   // try get value from memory cache
   return value, hasValue;
}

func RedisGetValue(key string) (string, bool) {
   var value string
   var hasValue bool

   // try get value from redis
   return value, hasValue;
}

func MysqlGetValue(key string) (string, bool){
   var value string
   var hasValue bool

   // try get value from mysql database
   return value, hasValue;
}

這三個(gè)XXXGetValue函數(shù),與Handler具有相同的函數(shù)簽名列荔,但不需要顯式的聲明其和Handler是等價(jià)的敬尺,這也是go語言的特性之一。

這里略去了具體操作內(nèi)存贴浙、redis砂吞、mysql的代碼,它們不是重點(diǎn)悬而。

將Receiver組織為鏈?zhǔn)浇Y(jié)構(gòu)

func GetValueByChain(key string, functions ...Handler) string{
   for _, f := range functions{
      value, ok := f(key)
      if ok{
         return value
      }
   }
   return ""
}

因?yàn)楹瘮?shù)是一等公民呜舒,可以作為參數(shù)傳給另一個(gè)函數(shù)锭汛,所以我們就可以把Handler函數(shù)按處理順序傳參給處理函數(shù)笨奠,變成一個(gè)鏈。

Sender調(diào)用

最后唤殴,Sender調(diào)用GetValueByChain函數(shù)般婆。

func main() {
   value := GetValueByChain("key", MemoryGetValue, RedisGetValue, MysqlGetValue)
}

這里本來只有一行代碼。

加了一個(gè)main函數(shù)朵逝,只是為了上面的代碼可以被放放在一個(gè)go文件中并且沒有編譯錯(cuò)誤蔚袍。

使用函數(shù)式的實(shí)現(xiàn),可以結(jié)合語言特性配名,讓編程更輕盈啤咽,更優(yōu)雅。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末渠脉,一起剝皮案震驚了整個(gè)濱河市宇整,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌芋膘,老刑警劉巖鳞青,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異为朋,居然都是意外死亡臂拓,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門习寸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胶惰,“玉大人,你說我怎么就攤上這事霞溪》踔停” “怎么了精钮?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長剃斧。 經(jīng)常有香客問我轨香,道長,這世上最難降的妖魔是什么幼东? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任间狂,我火速辦了婚禮蜒简,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己特漩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布趁啸。 她就那樣靜靜地躺著巨缘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪散庶。 梳的紋絲不亂的頭發(fā)上蕉堰,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音悲龟,去河邊找鬼屋讶。 笑死,一個(gè)胖子當(dāng)著我的面吹牛须教,可吹牛的內(nèi)容都是我干的皿渗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼轻腺,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼乐疆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起贬养,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤挤土,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后煤蚌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耕挨,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年尉桩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了筒占。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蜘犁,死狀恐怖翰苫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤奏窑,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布导披,位于F島的核電站,受9級(jí)特大地震影響埃唯,放射性物質(zhì)發(fā)生泄漏撩匕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一墨叛、第九天 我趴在偏房一處隱蔽的房頂上張望止毕。 院中可真熱鬧,春花似錦漠趁、人聲如沸扁凛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谨朝。三九已至,卻和暖如春甥绿,著一層夾襖步出監(jiān)牢的瞬間字币,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工妹窖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纬朝,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓骄呼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親判没。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蜓萄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353