日常工作中免不了使用設(shè)計(jì)模式崎场,那么你使用了哪些設(shè)計(jì)模式呢?
設(shè)計(jì)模式是什么干厚?
設(shè)計(jì)模式是一種在軟件設(shè)計(jì)中對(duì)常見(jiàn)問(wèn)題的通用解決方案螃宙。
它們是經(jīng)過(guò)驗(yàn)證的、可重用的設(shè)計(jì)思想挂捅,可以幫助解決開(kāi)發(fā)過(guò)程中遇到的各種問(wèn)題堂湖。
設(shè)計(jì)模式提供了一種共同的詞匯表和方法論状土,讓不同團(tuán)隊(duì)的開(kāi)發(fā)人員能夠更有效地溝通和協(xié)作蒙谓,從而提高軟件的穩(wěn)定性退盯、可靠性和可維護(hù)性。
整體來(lái)看慰照,設(shè)計(jì)模式包含了如下 22 種琉朽,主要分為三大類
- 創(chuàng)造型
- 結(jié)構(gòu)型
- 行為型
[圖片上傳失敗...(image-ca8a5e-1697122452141)]
看上去很多種,實(shí)際上咱們實(shí)際仔細(xì)去看每種模式的思想和細(xì)節(jié)的時(shí)候墅垮,能夠發(fā)現(xiàn)其實(shí)我們?nèi)粘9ぷ髦杏杏玫礁皇遣恢涝瓉?lái)是應(yīng)用了設(shè)計(jì)模式
有道無(wú)術(shù)術(shù)可求,有術(shù)無(wú)道止于術(shù) 灾梦,那么先來(lái)學(xué)習(xí)學(xué)習(xí)每種設(shè)計(jì)模式的思想妓笙,以及 GO 語(yǔ)言實(shí)現(xiàn)的 demo
創(chuàng)建型模式
1. 工廠模式
工廠模式 解決了在不指定具體類的情況下創(chuàng)建產(chǎn)品對(duì)象的問(wèn)題
案例:
寫一個(gè)工廠,可以生產(chǎn)車萧福,目前這個(gè)工廠可以生產(chǎn) bmw 和 benz 辈赋,那么我們需要獲取一輛車的時(shí)候,就直接去車廠拿車即可
2. 抽象工廠模式
它能創(chuàng)建一系列相關(guān)的對(duì)象悟民, 而無(wú)需指定其具體類
案例:
一個(gè)大賣場(chǎng)焕蹄,有衣服腻脏,有 鞋子,有 NB 品牌永品,有 Nike 品牌,此時(shí)我們就可以使用抽象工廠钾麸,抽象衣服炕桨,鞋子,每一個(gè)品牌自行去實(shí)現(xiàn)具體的衣服和鞋子
3. 生成器模式
能夠分步驟創(chuàng)建復(fù)雜對(duì)象
案例:
建一座建筑钥平,無(wú)論你是冰室姊途,還是住房,是非常復(fù)雜的立叛,我們演示簡(jiǎn)化為 4 個(gè)步驟贡茅,每個(gè)步驟都會(huì)創(chuàng)建新的對(duì)象,大體會(huì)經(jīng)歷如下步驟
- 搭建框架
- 裝修
- 安裝門
- 安裝床
4. 原型模式
能夠復(fù)制已有對(duì)象彤叉, 而又無(wú)需使代碼依賴它們所屬的類
案例:
此時(shí)可以想到我們的程序目錄村怪,和目錄下的文件,是否可以通過(guò)這種方式實(shí)現(xiàn)呢柬焕?
程序的目錄和文件梭域,能夠滿足遞歸的結(jié)構(gòu),目錄和文件富玷,都是同樣的結(jié)構(gòu)
5. 單例模式
能夠保證一個(gè)類只有一個(gè)實(shí)例, 并提供一個(gè)訪問(wèn)該實(shí)例的全局節(jié)點(diǎn)
單例實(shí)例會(huì)在結(jié)構(gòu)體首次初始化時(shí)創(chuàng)建雀鹃,若多個(gè)協(xié)程創(chuàng)建励两,如何保證協(xié)程安全呢?
package main
import (
"fmt"
"sync"
)
var lock sync.Mutex
var one sync.Once
type Single struct {
}
// 此時(shí)創(chuàng)建的 SingleInstance 默認(rèn)為 零值傅瞻, 也就是 nil
var SingleInstance *Single
// getOneInstance 顯示使用 鎖的方式盲憎,保證線程安全
func getOneInstance() *Single {
if SingleInstance == nil {
// 此處可能會(huì)有多個(gè)協(xié)程進(jìn)來(lái)
lock.Lock()
defer lock.Unlock()
// 此處再繼續(xù) 判斷 SingleInstance 是否為 nil,是因?yàn)榭赡芷渌麉f(xié)程已經(jīng)拿到鎖掸读,且初始化好了 SingleInstance 后宏多,當(dāng)前協(xié)程才拿到鎖
if SingleInstance == nil {
fmt.Println("getOneInstance: Create SingleInstance successfully ...")
SingleInstance = &Single{}
} else {
fmt.Println("1 getOneInstance: SingleInstance has been created ...")
}
}else {
fmt.Println("2 getOneInstance: SingleInstance has been created ...")
}
return SingleInstance
}
// getTwoInstance 使用 sync.Once 達(dá)到同樣的效果
func getTwoInstance() *Single {
if SingleInstance == nil {
fmt.Println("getTwoInstance: in SingleInstance == nil ...")
one.Do(func() {
// 因此 one.Do 只會(huì)執(zhí)行一次,因此不會(huì)出現(xiàn) getOneInstance 的情況肾请,因此此處無(wú)需判斷 SingleInstance 是否為 nil
fmt.Println("getTwoInstance: Create SingleInstance successfully ...")
SingleInstance = &Single{}
})
} else {
fmt.Println("getTwoInstance: SingleInstance has been created ...")
}
return SingleInstance
}
func main() {
for i := 0; i < 20; i++ {
//getOneInstance()
getTwoInstance()
}
fmt.Scanln()// 輸出回車就會(huì)結(jié)束
}
5_single_instance>go run main.go
getTwoInstance: in SingleInstance == nil ...
getTwoInstance: Create SingleInstance successfully ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
getTwoInstance: SingleInstance has been created ...
結(jié)構(gòu)型模式
6. 適配器模式
讓接口不兼容的對(duì)象能夠相互合作
案例:
可能我們都用過(guò)生活中的適配器吧铛铁,我們手機(jī)是 Type C 的接口却妨,電腦是 USB 的接口,那么這個(gè)時(shí)候倍权,如何讓 TypeC 的接口和 USB 的接口連接上呢捞烟?這個(gè)時(shí)候就可以使用適配器來(lái)處理
7. 橋接模式
可將一個(gè)大類或一系列緊密相關(guān)的類拆分為抽象和實(shí)現(xiàn)兩個(gè)獨(dú)立的層次結(jié)構(gòu), 從而能在開(kāi)發(fā)時(shí)分別使用 案例:
不同的顯示器要接入計(jì)算機(jī)默辨,那么計(jì)算機(jī)可以獨(dú)立開(kāi)發(fā)苍息,顯示器也可以獨(dú)立開(kāi)發(fā)壹置,無(wú)論計(jì)算機(jī)里面有 windows 的蒸绩,還是 mac 的 仍然支持設(shè)置 顯示器
demo 7
8. 組合模式
使用它將對(duì)象組合成樹狀結(jié)構(gòu)铃肯, 并且能像使用獨(dú)立對(duì)象一樣使用它們
案例:
咱們的目錄樹中有 目錄押逼,有 文件, 目錄可以進(jìn)行查詢挑格,文件也是可以進(jìn)行查詢沾歪,將他們組合起來(lái),他們各自仍然是獨(dú)立的對(duì)象
9. 代理模式
能夠提供對(duì)象的替代品或其占位符
案例:
對(duì)于 nginx 反向代理很熟悉吧挫望,咱們手?jǐn)]一個(gè)簡(jiǎn)單的反向代理磁椒,運(yùn)用代理模式
10. 裝飾器模式
允許你通過(guò)將對(duì)象放入包含行為的特殊封裝對(duì)象中來(lái)為原對(duì)象綁定新的行為
案例:
年輕人喜歡喝奶茶泉哈,不同的口味不同的配置有不同的價(jià)格,喝奶茶丛晦,有原味的,有加珍珠的匹层,有加椰果的斧吐,有加奶的 ,各有各的價(jià)格
那么 奶茶 和 珍珠煤率,椰果,奶 是相互獨(dú)立的洋只,各自是一個(gè)獨(dú)立的對(duì)象 我們可以在珍珠對(duì)象中,放入奶茶對(duì)象肢扯,進(jìn)而達(dá)到 奶茶中加珍珠担锤,加椰果,加奶 達(dá)到不同的價(jià)格
11. 外觀模式
能為程序庫(kù)铭腕、 框架或其他復(fù)雜類提供一個(gè)簡(jiǎn)單的接口
案例:
咱們?nèi)ャy行存錢多糠,取錢,表面上看著很簡(jiǎn)單夹孔,一進(jìn)一出即可,殊不知銀行后面的內(nèi)部系統(tǒng)之間復(fù)雜的交互只怎,我們簡(jiǎn)化一下 例如 銀行后面涉及到 賬戶系統(tǒng)怜俐,檢測(cè)系統(tǒng),數(shù)據(jù)庫(kù)系統(tǒng)盾沫,通知系統(tǒng) 這個(gè)時(shí)候 就可以使用 外觀模式殿漠,對(duì)于客戶端來(lái)說(shuō)使用非常簡(jiǎn)單,無(wú)需關(guān)注其內(nèi)部復(fù)雜系統(tǒng)
12. 享元模式
通過(guò)共享多個(gè)對(duì)象所共有的相同狀態(tài)
案例:
設(shè)計(jì)一個(gè)足球比賽游戲蕾哟,A 隊(duì)隊(duì)服是 紅色莲蜘,B 隊(duì)隊(duì)服是 藍(lán)色,且整個(gè)隊(duì)伍就只有一個(gè)套衣服 逐哈,此處就應(yīng)用了享元模式
如果不應(yīng)用享元模式,那么我們每一個(gè)人都要 new 一套衣服昂秃,咱確實(shí)沒(méi)有必要這樣做
行為模式
13. 命令模式
將請(qǐng)求轉(zhuǎn)換為一個(gè)包含與請(qǐng)求相關(guān)的所有信息的獨(dú)立對(duì)象
案例:
咱們以插件的方式來(lái)注入到程序中,如 我們平日看電視肠骆,需要按按鈕,按鈕上有各種按鍵嘴瓤,例如開(kāi)機(jī)鍵莉钙,關(guān)機(jī)鍵
另外,這個(gè)按鍵又是對(duì)于哪些設(shè)備生效呢?此處咱們是對(duì) TV 生效刻获,可以使用命令模式,很好的插入這些相關(guān)對(duì)象
14. 策略模式
讓你定義一系列算法蝎毡, 并將每種算法分別放入獨(dú)立的類中, 以使算法的對(duì)象能夠相互替換
案例:
咱們知道緩存的處理方式别垮,有 FIFO扎谎,LFU,LRU胧奔, 那么當(dāng)我們將數(shù)據(jù)載入緩存的時(shí)候预吆,使用的算法進(jìn)行切換了,我們?nèi)匀恍枰@個(gè)緩存是可以正常處理的拐叉,這個(gè)時(shí)候,咱們就可以使用策略模式
又如我們需要取到一個(gè)目的地宿礁,我們可以坐飛機(jī)蔬芥,可以乘高鐵红且,也可以走路去涤姊,在過(guò)程中仍然可以隨意切換交通方式,最終壁酬,我們都是抵達(dá)目的地恨课,沒(méi)有問(wèn)題,同樣也可以使用策略模式
15. 模板模式
在超類中定義一個(gè)算法的框架希俩, 允許子類在不修改結(jié)構(gòu)的情況下重寫算法的特定步驟
案例:
模板的方式纲辽,相信我們平日用的也非常多,舉個(gè)例子我們就能夠很好的感受到
我們要獲取消息拖吼,保存消息到緩存,生成消息回復(fù)篙议,發(fā)送消息怠硼,這幾個(gè)步驟不變的情況下,我們可以使用 微信吩愧,可以使用企業(yè)微信增显,自然也是可以使用飛書來(lái)處理
我們生成 源 msg,期望放到緩存中同云,生成具體的回復(fù)信息,將消息發(fā)送出去 對(duì)于這種步驟固定星澳,但是對(duì)于每一步驟期望有自己的實(shí)現(xiàn)方式的旱易,期望去重寫具體的實(shí)現(xiàn)方式的腿堤,可以使用模板方法
獲取到信息之后笆檀,wechat ,wework酗洒,lark 有不同的處理方式枷遂,但是他們的整體處理結(jié)構(gòu)是一樣的
16. 迭代器模式
讓你能在不暴露集合底層表現(xiàn)形式 (列表、 棧和樹等) 的情況下遍歷集合中所有的元素
案例:
我們提供出去的接口矩桂,不期望別人能看到我們自身的數(shù)據(jù)結(jié)構(gòu)痪伦,我們就可以使用迭代器的方式來(lái)進(jìn)行處理,可以隱藏實(shí)際的數(shù)據(jù)結(jié)構(gòu)
17. 觀察者模式
允許你定義一種訂閱機(jī)制, 可在對(duì)象事件發(fā)生時(shí)通知多個(gè) “觀察” 該對(duì)象的其他對(duì)象
案例:
這種設(shè)計(jì)模式應(yīng)用很多笆制,我們舉例一個(gè)食堂吃飯的例子
多個(gè)員工觀察食堂,食堂做好菜之后 訂閱的員工都能夠收到通知在辆,員工便傾巢而出
18. 責(zé)任鏈模式
允許你將請(qǐng)求沿著處理者鏈進(jìn)行發(fā)送证薇。 收到請(qǐng)求后浑度, 每個(gè)處理者均可對(duì)請(qǐng)求進(jìn)行處理鸦概, 或?qū)⑵鋫鬟f給鏈上的下個(gè)處理者
案例:
例如處理一件事情,有一個(gè)固定的流程先慷,正如一個(gè)新員工入職
員工入職可以看做是一個(gè)責(zé)任鏈咨察, 前臺(tái)報(bào)道,人事制度宣講摄狱,合同部合同簽訂无午,送入具體部門 , 這種部門職責(zé)明確宪迟,鏈路清晰踊跟,可以使用 責(zé)任鏈模式,允許你將請(qǐng)求沿著處理者鏈進(jìn)行發(fā)送 對(duì)于新員工來(lái)說(shuō)商玫,只需要知道去去找前臺(tái)報(bào)道即可
19. 備忘錄模式
允許在不暴露對(duì)象實(shí)現(xiàn)細(xì)節(jié)的情況下保存和恢復(fù)對(duì)象之前的狀態(tài)。
案例: 例如某白領(lǐng)使用備忘錄袭异,記錄了 1 炬藤,2 ,3 條信息上真,然后想調(diào)出 2 快照來(lái)進(jìn)行查看
20. 中介者模式
能讓你減少對(duì)象之間混亂無(wú)序的依賴關(guān)系羹膳。 該模式會(huì)限制對(duì)象之間的直接交互, 迫使它們通過(guò)一個(gè)中介者對(duì)象進(jìn)行合作陵像。
案例:
醫(yī)院里面有很多不同職業(yè)的人來(lái)看病,如何保證用戶進(jìn)入醫(yī)生辦公室發(fā)生沖突呢妻怎?
這個(gè)時(shí)候就有一個(gè)醫(yī)院服務(wù)人員來(lái)進(jìn)行管理泞歉,負(fù)責(zé)和不同的職業(yè)的病人溝通, 雖然病人之間沒(méi)有溝通偿洁,但是他們依然能有有序的進(jìn)入到醫(yī)生辦公室內(nèi)看病沟优,此時(shí)醫(yī)院服務(wù)人員就是一個(gè)中介者
21. 狀態(tài)模式
讓你能在一個(gè)對(duì)象的內(nèi)部狀態(tài)變化時(shí)改變其行為, 使其看上去就像改變了自身所屬的類一樣
案例:
售賣機(jī)暫時(shí)只售賣一種從產(chǎn)品挠阁,有 4 種狀態(tài)溯饵,沒(méi)貨丰刊,有貨增拥,正在請(qǐng)求商品,已投幣
對(duì)于不同的狀態(tài)秩仆,應(yīng)對(duì)不同的動(dòng)作
22. 訪問(wèn)者模式
將算法與其所作用的對(duì)象隔離開(kāi)來(lái)
案例:
目前有 3 種結(jié)構(gòu), Dog澄耍,Cat晌缘,Monkey 都實(shí)現(xiàn)了 IAnimal interface,訪問(wèn)者有 AreaVs(計(jì)算面積)选酗,VolumeVs(計(jì)算體積),ColorVs (計(jì)算顏色) 都實(shí)現(xiàn)了 IVisitor interface
以后如果需要類似于增加計(jì)算體脂率的岳枷,那么就可以加一個(gè) visitor 即可,且對(duì)其他的訪問(wèn)者和結(jié)構(gòu)沒(méi)有影響
如果需要增加結(jié)構(gòu)氢烘,例如增加 pig 家厌,那么直接去實(shí)現(xiàn) Animal 即可椎工,對(duì)其他的結(jié)構(gòu)和訪問(wèn)者沒(méi)有影響
有沒(méi)有覺(jué)得很巧妙呢?
歡迎點(diǎn)贊维蒙,關(guān)注,收藏
朋友們殖熟,你的支持和鼓勵(lì)斑响,是我堅(jiān)持分享钳榨,提高質(zhì)量的動(dòng)力
[圖片上傳失敗...(image-d67a3e-1697122452141)]
好了纽门,本次就到這里
技術(shù)是開(kāi)放的,我們的心態(tài)饼齿,更應(yīng)是開(kāi)放的蝙搔。擁抱變化,向陽(yáng)而生杂瘸,努力向前行。
我是阿兵云原生敌土,歡迎點(diǎn)贊關(guān)注收藏运翼,下次見(jiàn)~