Go設計模式(19)-模板模式

模板模式定義演算法骨架,使用上有兩個特徵,一是要繼承演算法骨架,達到複用的目的;二是具體的演算法步驟在子類中實現,達到擴充套件的目的。

UML類圖位置:https://www。processon。com/view/link/60d29bf3e401fd49502afd25

本文程式碼連結為:https://github。com/shidawuhen/asap/blob/master/controller/design/19template。go

1。定義

1。1模板模式

模板模式

:定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。

UML

Go設計模式(19)-模板模式

1。2分析

模板模式的UML圖幾乎是最簡單的了。

**模板方法模式可以讓子類在不改變演算法整體結構的情況下,重新定義演算法中的某些步驟。**TemplateMethod是演算法骨架,PrimitiveOperation1和PrimitiveOperation2是骨架中的某些步驟。

在模板模式經典的實現中,模板方法定義為 final,可以避免被子類重寫。需要子類重寫的方法定義為 abstract,可以強迫子類去實現。

以前用這種定義好演算法骨架,具體實現在不同子類的方案時,一般使用的是工廠方法加代理模式。工廠方法能夠提供更多的靈活性,但如果一個演算法骨架中有10個具體演算法,總不能讓工廠生產10個不同的物件吧。所以如果演算法骨架中有多個具體演算法,而這些演算法又是高內聚的,用模板模式就很合適。

2。使用場景

業務開發場景中,模板模式使用頻率並不高,但是在框架方面,還是使用的比較頻繁的。

先查看了Gin原始碼Gin原始碼剖析,發現用的不是模板模式,其實完全沒用啥設計模式,算是用了里氏替換原則。

主框架有Handler介面,用於做路由解析、對應邏輯執行與返回。

type Handler interface { ServeHTTP(ResponseWriter, *Request)}

Gin中的engin實現該介面

// ServeHTTP conforms to the http。Handler interface。func (engine *Engine) ServeHTTP(w http。ResponseWriter, req *http。Request) { c := engine。pool。Get()。(*Context) c。writermem。reset(w) c。Request = req c。reset() engine。handleHTTPRequest(c) engine。pool。Put(c)}

之所以說沒有使用模板模式,

主要是因為並沒有繼承演算法框架

後來想想Go語言沒有繼承,沒法實現經典款模板方法。雖然可以用組合實現模板方法,但無法控制對演算法框架的重寫、也無法強迫子類重寫演算法實現,感覺價值不大。有很多更好的方案能夠實現目的。

3。程式碼實現

雖然沒什麼特別好的case,但是程式碼還是要寫一下的。參考大話設計模式,寫一個試卷場景吧。試卷內容確定,但試卷答案不定。

package mainimport “fmt”/** * @Author: Jason Pang * @Description: 試卷 */type Examination struct { //函式變數,回答問題1 Answer1 func() //函式變數,回答問題2 Answer2 func()}/** * @Author: Jason Pang * @Description: 問題列表,也是演算法骨架 * @receiver e */func (e *Examination) Questions() { fmt。Println(“第一題:誰是最帥的人?”) e。Answer1() fmt。Println(“第二題:生活的意義是什麼?”) e。Answer2()}/** * @Author: Jason Pang * @Description: 真正做試卷 */type ExamplationDo struct { Examination}/** * @Author: Jason Pang * @Description: 寫答案1 * @receiver d */func (d *ExamplationDo) Answer1() { fmt。Println(“答案:我自己”)}/** * @Author: Jason Pang * @Description: 寫答案2 * @receiver d */func (d *ExamplationDo) Answer2() { fmt。Println(“答案:躺平”)}func main() { e := &ExamplationDo{} //需要對父類函式進行賦值 e。Examination。Answer1 = e。Answer1 e。Examination。Answer2 = e。Answer2 e。Questions()}

輸出:

➜ myproject go run main。go

第一題:誰是最帥的人?

答案:我自己

第二題:生活的意義是什麼?

答案:躺平

上面的程式碼使用一些技巧才能實現模板模式。父類Examination實現了演算法骨架,同時包含兩個函式變數Answer1和Answer2,代表演算法實現。子類ExamplationDo實現了Answer1和Answer2,並

將這兩個函式賦值給父類的函式變數

總結

模板模式有兩大作用:複用和擴充套件。其中,複用指的是,所有的子類可以複用父類中提供的模板方法的程式碼。擴充套件指的是,框架透過模板模式提供功能擴充套件點,讓框架使用者可以在不修改框架原始碼的情況下,基於擴充套件點定製化框架的功能。

最後

大家如果喜歡我的文章,可以關注我的公眾號(程式設計師麻辣燙)

我的個人部落格為:https://shidawuhen。github。io/

往期文章回顧:

招聘

位元組跳動|內推大放送

位元組跳動|今日頭條廣州服務端研發工程師內推

位元組跳動|抖音電商急招上海前端開發工程

位元組跳動|抖音電商上海資深服務端開發工程師-交易

位元組跳動|抖音電商武漢服務端(高階)開發工程師

位元組跳動|飛書大客戶產品經理內推咯

位元組跳動|抖音電商服務端技術崗位虛位以待

位元組跳動招聘專題

設計模式

Go設計模式(18)-觀察者模式

Go設計模式(17)-享元模式

Go設計模式(16)-組合模式

Go設計模式(15)-門面模式

Go設計模式(14)-介面卡模式

Go設計模式(13)-裝飾器模式

Go設計模式(12)-橋接模式

Go設計模式(11)-代理模式

Go設計模式(10)-原型模式

Go設計模式(9)-建造者模式

Go設計模式(8)-抽象工廠

Go設計模式(7)-工廠模式

Go設計模式(6)-單例模式

Go設計模式(5)-類圖符號表示法

Go設計模式(4)-程式碼編寫最佳化

Go設計模式(4)-程式碼編寫

Go設計模式(3)-設計原則

Go設計模式(2)-面向物件分析與設計

Go設計模式(1)-語法

語言

再也不怕獲取不到Gin請求資料了

一文搞懂pprof

Go工具之generate

Go單例實現方案

Go通道實現原理

Go定時器實現原理

Beego框架使用

Golang原始碼BUG追查

Gin框架簡潔版

Gin原始碼剖析

架構

分頁複選設計的坑

支付接入常規問題

限流實現2

秒殺系統

分散式系統與一致性協議

微服務之服務框架和註冊中心

淺談微服務

限流實現1

CDN請求過程詳解

常用快取技巧

如何高效對接第三方支付

演算法總結

儲存

一文搞懂MySQL資料庫分庫分表

MySQL開發規範

Redis實現分散式鎖

事務原子性、一致性、永續性的實現原理

InnoDB鎖與事務簡析

網路

HTTP2。0基礎教程

HTTPS配置實戰

HTTPS連線過程

TCP效能最佳化

工具

GoLand實用技巧

根據mysql表自動生成go struct

Markdown編輯器推薦-typora

讀書筆記

《毛選》推薦

原則

資治通鑑

敏捷革命

如何鍛鍊自己的記憶力

簡單的邏輯學-讀後感

熱風-讀後感

論語-讀後感

孫子兵法-讀後感

思考

對過去的一點回顧

對寫部落格的一些思考

晚上打119的經歷

為動員一切力量爭取勝利而鬥爭

反對自由主義

實踐論

評價自己的標準

2020部落格總結

服務端團隊假期值班方案

專案流程管理

對專案管理的一些看法

對產品經理的一些思考

關於程式設計師職業發展的思考

關於程式碼review的思考