十種 Golang 演示設(shè)計(jì)模式詳細(xì)介紹
作者 | knightwwang
Golang演示常見的十種設(shè)計(jì)模式的應(yīng)用場景。
1. 單例模式(Singleton Pattern)
單例模式是一種創(chuàng)建型設(shè)計(jì)模式,它限制了實(shí)例化類的對(duì)象個(gè)數(shù),確保在任何情況下,一個(gè)類只有一個(gè)實(shí)例,并且提供一個(gè)全局訪問點(diǎn)。這種模式在需要全局狀態(tài)控制或共享資源訪問時(shí)非常有用。
特點(diǎn):
- 只有一個(gè)實(shí)例對(duì)象。
- 必須自行創(chuàng)建實(shí)例對(duì)象。
- 必須提供一個(gè)訪問該實(shí)例的全局訪問點(diǎn)。
優(yōu)點(diǎn):
- 確保在應(yīng)用中,資源或狀態(tài)的全局唯一性。
- 減少系統(tǒng)資源消耗,提高系統(tǒng)效率。
缺點(diǎn):
- 反模塊化,因?yàn)閱卫龑?duì)象需要被多個(gè)客戶端引用,這違反了高內(nèi)聚低耦合的設(shè)計(jì)原則。
- 難以測試,因?yàn)閱卫龑?duì)象的生命周期與應(yīng)用相同,這使得在單元測試中進(jìn)行隔離測試變得困難。
應(yīng)用場景:
- 配置管理器:在應(yīng)用程序中,配置信息通常只需要一個(gè)實(shí)例來管理,這樣可以保證配置信息的一致性。
- 連接池:數(shù)據(jù)庫連接池需要限制數(shù)據(jù)庫連接的數(shù)量,以避免過多的連接消耗資源。
- 日志記錄器:日志系統(tǒng)通常只需要一個(gè)實(shí)例來記錄應(yīng)用程序的日志信息,以避免日志信息的冗余和混亂。
- 硬件管理器:對(duì)于某些硬件設(shè)備,如打印機(jī)或掃描儀,可能只需要一個(gè)管理器來控制對(duì)它們的訪問。
- 應(yīng)用狀態(tài)管理:在某些應(yīng)用中,需要全局的狀態(tài)管理,如用戶會(huì)話管理或權(quán)限驗(yàn)證狀態(tài)。
// 定義一個(gè)結(jié)構(gòu)體Singleton,用于存儲(chǔ)單例的實(shí)例數(shù)據(jù)
type singleton struct {
value string // 這里可以存儲(chǔ)單例對(duì)象的任何數(shù)據(jù)
}
// 定義一個(gè)全局變量instance,用于存儲(chǔ)單例的實(shí)例
var instance *singleton
// getInstance函數(shù)用于獲取單例的實(shí)例
// 如果instance為nil,則創(chuàng)建一個(gè)新的singleton實(shí)例
// 否則,返回已存在的實(shí)例
func getInstance() *singleton {
if instance == nil {
instance = &singleton{value: "unique instance"} // 這里初始化singleton實(shí)例
}
return instance // 返回單例的實(shí)例
}
func main() {
// 獲取單例的實(shí)例
singletonInstance := getInstance()
fmt.Println(singletonInstance.value) // 輸出: unique instance
// 再次獲取單例的實(shí)例,將返回相同的實(shí)例
anotherInstance := getInstance()
if singletonInstance == anotherInstance {
fmt.Println("Both instances are the same") // 輸出: Both instances are the same
}
}
在并發(fā)環(huán)境下如果沒有適當(dāng)?shù)耐綑C(jī)制,多個(gè)goroutine可能會(huì)同時(shí)檢測到instance為nil并嘗試創(chuàng)建新的實(shí)例,從而導(dǎo)致創(chuàng)建多個(gè)實(shí)例。 為了解決這個(gè)問題,可以使用sync.Once,它確保在并發(fā)環(huán)境中只執(zhí)行一次初始化操作。
// 定義一個(gè)結(jié)構(gòu)體Singleton,用于存儲(chǔ)單例的實(shí)例數(shù)據(jù)
type singleton struct {
value string // 這里可以存儲(chǔ)單例對(duì)象的任何數(shù)據(jù)
}
// 定義一個(gè)Once對(duì)象,用于確保初始化操作只執(zhí)行一次
var once sync.Once
// 定義一個(gè)全局變量instance,用于存儲(chǔ)單例的實(shí)例
var instance *singleton
// 初始化函數(shù),由Once.Do調(diào)用
func initSingleton() {
instance = &singleton{value: "unique instance"} // 這里初始化singleton實(shí)例
}
// getInstance函數(shù)用于獲取單例的實(shí)例
func getInstance() *singleton {
// 執(zhí)行initSingleton,確保instance只被初始化一次
once.Do(initSingleton)
return instance // 返回單例的實(shí)例
}
func main() {
// 獲取單例的實(shí)例
singletonInstance := getInstance()
fmt.Println(singletonInstance.value) // 輸出: unique instance
// 再次獲取單例的實(shí)例,將返回相同的實(shí)例
anotherInstance := getInstance()
if singletonInstance == anotherInstance {
fmt.Println("Both instances are the same") // 輸出: Both instances are the same
}
// 測試并發(fā)環(huán)境下的單例模式
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
singletonInstance := getInstance()
fmt.Println(singletonInstance.value)
}()
}
wg.Wait()
}
2. 工廠模式(Factory Pattern)
工廠模式是一種創(chuàng)建型設(shè)計(jì)模式,用于將對(duì)象的創(chuàng)建過程封裝起來,由子類決定實(shí)例化哪一個(gè)類。這種模式使得代碼結(jié)構(gòu)更加清晰,并且能夠輕松替換或擴(kuò)展產(chǎn)品類。
特點(diǎn):
- 封裝性:將對(duì)象的創(chuàng)建過程封裝在工廠類中。
- 擴(kuò)展性:通過繼承和多態(tài),可以輕松地添加新的產(chǎn)品類。
- 抽象性:工廠方法定義了創(chuàng)建對(duì)象的接口,但具體對(duì)象的創(chuàng)建由子類實(shí)現(xiàn)。
優(yōu)點(diǎn):
- 將對(duì)象的創(chuàng)建和使用分離,提高了模塊間的獨(dú)立性。
- 易于擴(kuò)展,增加新的產(chǎn)品類時(shí)不需要修改現(xiàn)有代碼,符合開閉原則。
缺點(diǎn):
- 每增加一個(gè)產(chǎn)品類,就需要增加一個(gè)具體的工廠類,這可能會(huì)導(dǎo)致類的數(shù)量急劇增加。
- 工廠類集中了所有實(shí)例的創(chuàng)建邏輯,可能會(huì)導(dǎo)致工廠類過于龐大。
應(yīng)用場景:
- 數(shù)據(jù)庫連接:根據(jù)不同的數(shù)據(jù)庫類型,如MySQL、PostgreSQL,創(chuàng)建相應(yīng)的數(shù)據(jù)庫連接對(duì)象。
- GUI組件:在圖形用戶界面開發(fā)中,不同的操作系統(tǒng)可能需要不同的組件實(shí)現(xiàn),工廠模式可以根據(jù)不同平臺(tái)創(chuàng)建相應(yīng)的組件。
- 支付網(wǎng)關(guān):根據(jù)不同的支付方式,如信用卡、PayPal、微信支付,創(chuàng)建相應(yīng)的支付處理對(duì)象。
- 圖像處理:在圖像處理軟件中,根據(jù)不同的文件格式,如JPEG、PNG,創(chuàng)建相應(yīng)的圖像處理器。
// 定義一個(gè)接口Product,它聲明了所有具體產(chǎn)品對(duì)象必須實(shí)現(xiàn)的操作
type Product interface {
operation() // 產(chǎn)品對(duì)象的操作
}
// 定義具體產(chǎn)品ConcreteProductA,實(shí)現(xiàn)了Product接口
type ConcreteProductA struct{}
func (p *ConcreteProductA) operation() {
fmt.Println("Operation of ConcreteProductA")
}
// 定義另一個(gè)具體產(chǎn)品ConcreteProductB,也實(shí)現(xiàn)了Product接口
type ConcreteProductB struct{}
func (p *ConcreteProductB) operation() {
fmt.Println("Operation of ConcreteProductB")
}
// 定義一個(gè)抽象工廠Creator,它聲明了工廠方法factoryMethod,用于創(chuàng)建產(chǎn)品對(duì)象
type Creator interface {
factoryMethod() Product // 工廠方法,用于創(chuàng)建產(chǎn)品對(duì)象
}
// 定義具體工廠CreatorA,實(shí)現(xiàn)了Creator接口
type CreatorA struct{}
func (c *CreatorA) factoryMethod() Product {
return &ConcreteProductA{} // 具體工廠CreatorA返回ConcreteProductA的實(shí)例
}
// 定義另一個(gè)具體工廠CreatorB,也實(shí)現(xiàn)了Creator接口
type CreatorB struct{}
func (c *CreatorB) factoryMethod() Product {
return &ConcreteProductB{} // 具體工廠CreatorB返回ConcreteProductB的實(shí)例
}
func main() {
// 創(chuàng)建具體工廠CreatorA的實(shí)例
creatorA := &CreatorA{}
productA := creatorA.factoryMethod()
productA.operation() // 調(diào)用產(chǎn)品A的操作
// 創(chuàng)建具體工廠CreatorB的實(shí)例
creatorB := &CreatorB{}
productB := creatorB.factoryMethod()
productB.operation() // 調(diào)用產(chǎn)品B的操作
}
3. 觀察者模式(Observer Pattern)
觀察者模式是一種行為設(shè)計(jì)模式,它定義了對(duì)象間的一種一對(duì)多的依賴關(guān)系,使得當(dāng)一個(gè)對(duì)象改變狀態(tài)時(shí),所有依賴于它的對(duì)象都會(huì)得到通知并自動(dòng)更新。這種模式非常適合于實(shí)現(xiàn)分布式事件處理系統(tǒng)。
特點(diǎn):
- 一對(duì)多關(guān)系:一個(gè)主題可以有多個(gè)觀察者。
- 抽象耦合:觀察者和主題之間是抽象耦合的,增加新的觀察者不會(huì)影響現(xiàn)有的系統(tǒng)。
- 動(dòng)態(tài)聯(lián)動(dòng):觀察者可以在任何時(shí)候加入或退出。
優(yōu)點(diǎn):
- 降低了對(duì)象之間的耦合度,主題與觀察者之間是松散耦合的。
- 擴(kuò)展性好,增加新的觀察者或主題類不影響現(xiàn)有的類。
缺點(diǎn):
- 當(dāng)觀察者對(duì)象很多時(shí),通知的分發(fā)可能會(huì)造成性能問題。
- 如果觀察者和主題之間的依賴關(guān)系過于復(fù)雜,會(huì)導(dǎo)致系統(tǒng)難以維護(hù)。
應(yīng)用場景:
- 事件監(jiān)聽系統(tǒng):在GUI應(yīng)用程序中,用戶界面組件(如按鈕、文本框等)可以作為觀察者,監(jiān)聽用戶的輸入事件。
- UI更新:在應(yīng)用程序中,當(dāng)數(shù)據(jù)模型發(fā)生變化時(shí),界面需要相應(yīng)地更新,使用觀察者模式可以自動(dòng)完成這一過程。
- 消息系統(tǒng):在即時(shí)通訊軟件中,當(dāng)有新消息到達(dá)時(shí),所有在線的用戶(觀察者)都會(huì)收到通知。
- 股票市場:股票價(jià)格更新時(shí),所有訂閱了該股票的投資者(觀察者)都會(huì)收到最新價(jià)格信息。
- 資源監(jiān)控:在系統(tǒng)監(jiān)控工具中,當(dāng)系統(tǒng)資源(如CPU、內(nèi)存使用率)超過設(shè)定閾值時(shí),監(jiān)控系統(tǒng)(觀察者)會(huì)收到通知并采取相應(yīng)措施。
// 定義Observer接口,它聲明了觀察者需要實(shí)現(xiàn)的Update方法
type Observer interface {
Update(string) // 當(dāng)主題狀態(tài)改變時(shí),此方法會(huì)被調(diào)用
}
// 定義Subject結(jié)構(gòu)體,它包含一個(gè)觀察者列表和方法來添加或通知觀察者
type Subject struct {
observers []Observer // 存儲(chǔ)觀察者的列表
}
// Attach方法用于將一個(gè)觀察者添加到觀察者列表中
func (s *Subject) Attach(observer Observer) {
s.observers = append(s.observers, observer)
}
// Notify方法用于通知所有觀察者主題狀態(tài)的改變
func (s *Subject) Notify(message string) {
for _, observer := range s.observers {
observer.Update(message) // 調(diào)用每個(gè)觀察者的Update方法
}
}
// 定義一個(gè)具體觀察者ConcreteObserver,它實(shí)現(xiàn)了Observer接口
type ConcreteObserverA struct {
name string
}
// 實(shí)現(xiàn)Observer接口的Update方法
func (c *ConcreteObserverA) Update(message string) {
fmt.Printf("%s received message: %s\n", c.name, message)
}
func main() {
// 創(chuàng)建主題對(duì)象
subject := &Subject{}
// 創(chuàng)建具體觀察者對(duì)象
observerA := &ConcreteObserverA{name: "Observer A"}
// 將觀察者添加到主題的觀察者列表中
subject.Attach(observerA)
// 當(dāng)主題狀態(tài)改變時(shí),通知所有觀察者
subject.Notify("State changed to State 1")
}
4. 裝飾者模式(Decorator Pattern)
裝飾者模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,允許用戶在不修改對(duì)象自身的基礎(chǔ)上,通過添加裝飾者對(duì)象來動(dòng)態(tài)地給對(duì)象添加額外的職責(zé)或功能。
特點(diǎn):
- 動(dòng)態(tài)擴(kuò)展:可以在運(yùn)行時(shí)動(dòng)態(tài)地給對(duì)象添加職責(zé)。
- 透明性:裝飾者模式不改變對(duì)象的接口,因此對(duì)客戶端來說是透明的。
- 靈活性:可以多個(gè)裝飾者組合使用,為對(duì)象添加多個(gè)職責(zé)。
優(yōu)點(diǎn):
- 增加對(duì)象的職責(zé)是動(dòng)態(tài)的、可撤銷的。
- 可以用多個(gè)裝飾者包裝一個(gè)對(duì)象,添加多個(gè)職責(zé)。
- 裝飾者和對(duì)象可以獨(dú)立變化,不會(huì)相互耦合。
缺點(diǎn):
- 過度使用裝飾者模式可能會(huì)使系統(tǒng)變得復(fù)雜,難以理解。
- 可能會(huì)引起多層裝飾者調(diào)用,影響性能。
應(yīng)用場景:
- 日志記錄:在不修改原有對(duì)象的基礎(chǔ)上,添加日志記錄功能。
- 緩存:為對(duì)象的某些方法添加緩存功能,以提高性能。
- 安全控制:為對(duì)象添加訪問控制,如權(quán)限檢查。
- 事務(wù)處理:為數(shù)據(jù)庫操作添加事務(wù)管理功能。
- 性能監(jiān)控:為對(duì)象的方法添加性能監(jiān)控功能,以分析性能瓶頸。
- 資源管理:為資源使用添加額外的管理功能,如連接池的管理。
// 定義Component接口,它是所有組件和裝飾者的基類
type Component interface {
operation() // 組件執(zhí)行的操作
}
// 定義具體組件ConcreteComponent,實(shí)現(xiàn)了Component接口
type ConcreteComponent struct{}
func (c *ConcreteComponent) operation() {
fmt.Println("ConcreteComponent: performing basic operation")
}
// 定義Decorator抽象結(jié)構(gòu)體,它包含一個(gè)Component接口類型的字段
type Decorator struct {
component Component // 用于組合Component接口
}
// 實(shí)現(xiàn)Decorator的operation方法,調(diào)用其Component的operation方法
func (d *Decorator) operation() {
if d.component != nil {
d.component.operation() // 調(diào)用被裝飾者的operation
}
}
// 定義具體裝飾者ConcreteDecoratorA,它嵌入了Decorator結(jié)構(gòu)體
type ConcreteDecoratorA struct {
Decorator // 繼承Decorator,實(shí)現(xiàn)裝飾功能
}
// 為ConcreteDecoratorA實(shí)現(xiàn)operation方法,添加額外的職責(zé)
func (cda *ConcreteDecoratorA) operation() {
cda.Decorator.operation() // 首先調(diào)用被裝飾者的operation
fmt.Println("ConcreteDecoratorA: added additional responsibilities")
}
func main() {
// 創(chuàng)建具體組件
component := &ConcreteComponent{}
// 創(chuàng)建裝飾者并關(guān)聯(lián)具體組件
decoratorA := &ConcreteDecoratorA{Decorator{component}}
// 執(zhí)行裝飾后的組件操作
decoratorA.operation()
}
5. 策略模式(Strategy Pattern)
策略模式是一種行為設(shè)計(jì)模式,它定義了一系列的算法,并將每一個(gè)算法封裝起來,使它們可以互相替換。策略模式讓算法獨(dú)立于使用它的客戶端。
特點(diǎn):
- 封裝變化:將變化的部分封裝起來,與穩(wěn)定部分分離。
- 多態(tài)性:使用多態(tài)來實(shí)現(xiàn)算法的替換。
- 替換性:在運(yùn)行時(shí)選擇使用哪個(gè)策略。
優(yōu)點(diǎn):
- 算法的變化獨(dú)立于使用算法的客戶端。
- 容易添加新算法而不影響客戶端。
缺點(diǎn):
- 客戶端必須了解所有策略類的差異,以便使用適當(dāng)?shù)牟呗浴?/li>
應(yīng)用場景:
- 算法選擇:在應(yīng)用程序中,根據(jù)不同的業(yè)務(wù)需求選擇不同的算法。
- 支付方式:在電子商務(wù)平臺(tái),根據(jù)用戶選擇提供不同的支付方式。
- 排序算法:在數(shù)據(jù)處理中,根據(jù)不同的數(shù)據(jù)特性選擇不同的排序算法。
- 路徑查找:在地圖服務(wù)中,根據(jù)不同的優(yōu)化標(biāo)準(zhǔn)(如時(shí)間最短、距離最短)選擇不同的路徑查找算法。
- 游戲AI:在游戲開發(fā)中,不同的敵人或角色使用不同的AI策略。
// 定義Strategy接口,它聲明了所有具體策略必須實(shí)現(xiàn)的algorithm方法
type Strategy interface {
algorithm() // 策略的算法方法
}
// 定義具體策略ConcreteStrategyA,實(shí)現(xiàn)了Strategy接口
type ConcreteStrategyA struct{}
func (c *ConcreteStrategyA) algorithm() {
fmt.Println("Executing Algorithm A")
}
// 定義另一個(gè)具體策略ConcreteStrategyB,也實(shí)現(xiàn)了Strategy接口
type ConcreteStrategyB struct{}
func (c *ConcreteStrategyB) algorithm() {
fmt.Println("Executing Algorithm B")
}
// 定義Context結(jié)構(gòu)體,它包含一個(gè)Strategy接口類型的字段
type Context struct {
strategy Strategy // 用于存儲(chǔ)當(dāng)前使用的策略
}
// 執(zhí)行策略的方法,通過Context中的strategy字段調(diào)用algorithm方法
func (c *Context) executeStrategy() {
c.strategy.algorithm() // 執(zhí)行當(dāng)前策略的算法
}
func main() {
// 創(chuàng)建Context對(duì)象
context := &Context{}
// 創(chuàng)建具體策略對(duì)象
strategyA := &ConcreteStrategyA{}
strategyB := &ConcreteStrategyB{}
// 將Context的策略設(shè)置為策略A
context.strategy = strategyA
context.executeStrategy() // 輸出: Executing Algorithm A
// 更換策略為策略B
context.strategy = strategyB
context.executeStrategy() // 輸出: Executing Algorithm B
}
6. 適配器模式(Adapter Pattern)
適配器模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,用于使原本不兼容的接口能夠一起工作。它通常涉及到一個(gè)客戶端使用一個(gè)期望的特定接口,而另一個(gè)類或組件提供了一個(gè)不同的接口。適配器模式通過創(chuàng)建一個(gè)中間層(適配器),將一個(gè)類的接口轉(zhuǎn)換成客戶端期望的另一個(gè)接口。
特點(diǎn):
- 接口轉(zhuǎn)換:適配器模式提供了將一個(gè)類的接口轉(zhuǎn)換成另一種接口的方式。
- 兼容性:解決了接口不兼容的問題,使得原本不能一起工作的類可以協(xié)同工作。
優(yōu)點(diǎn):
- 增加了類的兼容性,使得它們可以一起工作,即使它們的接口不兼容。
- 客戶端代碼不需要修改,通過適配器與目標(biāo)類交互。
缺點(diǎn):
- 過度使用適配器模式可能會(huì)使系統(tǒng)變得復(fù)雜,難以理解和維護(hù)。
- 適配器可能會(huì)引入性能開銷,尤其是在需要頻繁調(diào)用適配器方法的情況下。
應(yīng)用場景:
- 不同系統(tǒng)的集成:當(dāng)需要將兩個(gè)使用不同接口的系統(tǒng)集成時(shí),可以使用適配器模式。
- 第三方庫的集成:當(dāng)使用一個(gè)第三方庫,但其接口與現(xiàn)有系統(tǒng)不兼容時(shí),可以通過適配器模式進(jìn)行集成。
- 硬件設(shè)備控制:在硬件設(shè)備控制領(lǐng)域,不同的設(shè)備可能有不同的控制接口,適配器模式可以用來統(tǒng)一這些接口。
- 新舊系統(tǒng)遷移:在新舊系統(tǒng)遷移過程中,舊系統(tǒng)中的組件可能需要適配新系統(tǒng)的接口。
- 模塊化設(shè)計(jì):在模塊化設(shè)計(jì)中,適配器模式可以用來連接不同模塊,即使它們的接口不兼容。
// 定義Target接口,表示客戶端使用的特定領(lǐng)域相關(guān)的接口
type Target interface {
request() // 客戶端期望調(diào)用的方法
}
// 定義一個(gè)已經(jīng)存在的類Adaptee,它有自己的接口
type Adaptee struct{}
func (a *Adaptee) specificRequest() {
fmt.Println("Adaptee performs a specific request")
}
// 定義Adapter結(jié)構(gòu)體,它作為Target接口和Adaptee類之間的橋梁
type Adapter struct {
adaptee *Adaptee // 引用Adaptee對(duì)象
}
// Adapter實(shí)現(xiàn)了Target接口的request方法
// 該方法內(nèi)部委托給Adaptee的specificRequest方法
func (a *Adapter) request() {
if a.adaptee != nil {
a.adaptee.specificRequest() // 委托調(diào)用Adaptee的方法
}
}
func main() {
// 創(chuàng)建Adaptee對(duì)象
adaptee := &Adaptee{}
// 創(chuàng)建Adapter對(duì)象,并注入Adaptee對(duì)象
adapter := &Adapter{adaptee: adaptee}
// 客戶端使用Target接口,這里通過Adapter實(shí)現(xiàn)
var target Target = adapter
target.request() // 通過Adapter調(diào)用Adaptee的方法
}
7. 代理模式(Proxy Pattern)
代理模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,它為另一個(gè)對(duì)象提供一個(gè)代替或占位符,以控制對(duì)它的訪問。代理可以在不改變對(duì)象的代碼前提下,通過引入代理對(duì)象來間接訪問原始對(duì)象,從而在不直接暴露原始對(duì)象的情況下,提供額外的功能操作。
特點(diǎn):
- 間接訪問:通過代理對(duì)象來間接訪問原始對(duì)象。
- 職責(zé)分離:將控制邏輯與業(yè)務(wù)邏輯分離,代理對(duì)象負(fù)責(zé)控制邏輯,原始對(duì)象負(fù)責(zé)業(yè)務(wù)邏輯。
- 延遲初始化:代理可以在需要時(shí)才創(chuàng)建原始對(duì)象,實(shí)現(xiàn)延遲初始化。
優(yōu)點(diǎn):
- 降低了系統(tǒng)的耦合度,增強(qiáng)了對(duì)象的可控性。
- 可以為原始對(duì)象提供額外的安全控制或延遲加載等操作。
- 增加了代碼的可擴(kuò)展性,可以在不修改原始對(duì)象的情況下,通過引入新的代理類來擴(kuò)展功能。
缺點(diǎn):
- 增加了系統(tǒng)的復(fù)雜性,可能會(huì)讓系統(tǒng)設(shè)計(jì)變得更加復(fù)雜。
- 可能會(huì)引入性能開銷,尤其是在代理對(duì)象需要進(jìn)行復(fù)雜控制邏輯時(shí)。
應(yīng)用場景:
- 訪問控制:在需要對(duì)對(duì)象訪問進(jìn)行權(quán)限控制時(shí),可以使用代理模式。
- 延遲初始化:對(duì)于資源消耗較大的對(duì)象,可以使用代理模式實(shí)現(xiàn)延遲加載。
- 遠(yuǎn)程代理:為遠(yuǎn)程對(duì)象或網(wǎng)絡(luò)資源提供代理,隱藏對(duì)象位于不同地址空間的事實(shí)。
- 虛擬代理:為復(fù)雜的對(duì)象創(chuàng)建一個(gè)簡單的代理,以簡化訪問。
- 保護(hù)代理:控制對(duì)原始對(duì)象的訪問,提供訪問前后的附加操作。
- 智能引用:在訪問對(duì)象時(shí)進(jìn)行引用計(jì)數(shù),當(dāng)沒有引用時(shí)自動(dòng)釋放資源。
// 定義一個(gè)Subject接口,它聲明了真實(shí)主題和代理主題共有的接口。
type Subject interface {
request() // 聲明一個(gè)請求方法,真實(shí)主題和代理主題都會(huì)實(shí)現(xiàn)這個(gè)方法。
}
// RealSubject 結(jié)構(gòu)體實(shí)現(xiàn)了 Subject 接口,代表真實(shí)主題。
type RealSubject struct{}
// RealSubject 的 request 方法實(shí)現(xiàn)了 Subject 接口的 request 方法,用于執(zhí)行實(shí)際的操作。
func (r *RealSubject) request() {
fmt.Println("Real Subject") // 打印 "Real Subject" 表示真實(shí)主題正在被調(diào)用。
}
// Proxy 結(jié)構(gòu)體包含一個(gè)指向 RealSubject 的指針,它作為代理主題。
type Proxy struct {
realSubject *RealSubject // 代理主題包含一個(gè)對(duì)真實(shí)主題的引用,初始為 nil。
}
// Proxy 的 request 方法實(shí)現(xiàn)了 Subject 接口的 request 方法。
// 這個(gè)方法首先檢查 realSubject 是否為 nil,如果是,則創(chuàng)建 RealSubject 的實(shí)例。
// 然后,調(diào)用 realSubject 的 request 方法,從而間接地實(shí)現(xiàn)了 Subject 接口的 request 方法。
func (p *Proxy) request() {
if p.realSubject == nil { // 如果 realSubject 為 nil,說明還沒有創(chuàng)建真實(shí)主題的實(shí)例。
p.realSubject = &RealSubject{} // 創(chuàng)建 RealSubject 的實(shí)例,并賦值給 realSubject。
}
p.realSubject.request() // 調(diào)用真實(shí)主題的 request 方法。
}
8. 命令模式(Command Pattern)
命令模式是一種行為設(shè)計(jì)模式,它將一個(gè)請求或操作封裝為一個(gè)對(duì)象。這種模式可以解耦請求的發(fā)送者和接收者,讓它們不直接交互,而是通過命令對(duì)象來間接進(jìn)行通信。
特點(diǎn):
- 封裝性:命令模式將請求封裝為一個(gè)對(duì)象,隱藏了請求的具體實(shí)現(xiàn)細(xì)節(jié)。
- 擴(kuò)展性:可以方便地添加新的命令類,無需修改現(xiàn)有代碼。
- 靈活性:命令對(duì)象可以被存儲(chǔ)、傳遞、排隊(duì)、記錄和修改。
優(yōu)點(diǎn):
- 降低了系統(tǒng)耦合度,請求發(fā)送者和接收者之間通過命令對(duì)象交互。
- 增加了操作的靈活性,如支持撤銷、重做、事務(wù)等操作。
- 易于擴(kuò)展,可以獨(dú)立地添加新的命令。
缺點(diǎn):
- 可能會(huì)有大量的命令類,特別是命令的實(shí)現(xiàn)邏輯復(fù)雜時(shí)。
應(yīng)用場景:
- 事務(wù)處理:在需要支持事務(wù)操作的系統(tǒng)中,命令模式可以封裝事務(wù)請求,支持事務(wù)的提交和回滾。
- 撤銷操作:在需要撤銷功能的系統(tǒng)中,命令對(duì)象可以存儲(chǔ)狀態(tài),以便在需要時(shí)撤銷操作。
- 日志請求:在需要記錄用戶操作的系統(tǒng)中,命令對(duì)象可以記錄操作日志,用于審計(jì)或恢復(fù)操作。
- 批處理系統(tǒng):在批處理系統(tǒng)中,命令對(duì)象可以表示一個(gè)批處理任務(wù),支持任務(wù)的調(diào)度和執(zhí)行。
- 宏錄制:在需要宏錄制功能的系統(tǒng)中,命令對(duì)象可以封裝一系列操作,形成宏命令。
// 定義Command接口,它聲明了所有具體命令必須實(shí)現(xiàn)的Execute方法
type Command interface {
Execute() // 執(zhí)行命令的方法
}
// 定義Receiver結(jié)構(gòu)體,它將執(zhí)行命令的實(shí)際請求
type Receiver struct{}
func (r *Receiver) Action() {
fmt.Println("Receiver: Action")
}
// 定義ConcreteCommand結(jié)構(gòu)體,它實(shí)現(xiàn)了Command接口
// 每個(gè)具體命令都包含一個(gè)Receiver的引用,表示請求的接收者
type ConcreteCommand struct {
receiver *Receiver // 命令執(zhí)行的接收者
}
// ConcreteCommand實(shí)現(xiàn)Command接口的Execute方法
// 該方法調(diào)用Receiver的Action方法來執(zhí)行請求
func (c *ConcreteCommand) Execute() {
c.receiver.Action() // 執(zhí)行請求
}
// 定義Invoker結(jié)構(gòu)體,它負(fù)責(zé)調(diào)用命令對(duì)象的Execute方法
type Invoker struct {
command Command // 存儲(chǔ)命令對(duì)象
}
// 調(diào)用命令對(duì)象的Execute方法
func (i *Invoker) Invoke() {
i.command.Execute() // 執(zhí)行命令
}
func main() {
// 創(chuàng)建接收者對(duì)象
receiver := &Receiver{}
// 創(chuàng)建具體命令對(duì)象,并注入接收者
command := &ConcreteCommand{receiver: receiver}
// 創(chuàng)建調(diào)用者對(duì)象,并注入具體命令對(duì)象
invoker := &Invoker{command: command}
// 調(diào)用者執(zhí)行命令
invoker.Invoke() // 輸出: Receiver: Action
}
9. 組合模式(Composite Pattern)
組合模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,它允許你將對(duì)象組合成樹狀結(jié)構(gòu),以表示“部分-整體”的層次結(jié)構(gòu)。這種模式使得用戶可以一致地對(duì)待單個(gè)對(duì)象和對(duì)象組合。
特點(diǎn):
- 部分-整體層次結(jié)構(gòu):可以包含其他組合或葉節(jié)點(diǎn),形成樹狀結(jié)構(gòu)。
- 一致性:客戶端代碼可以一致地處理組合結(jié)構(gòu)和葉節(jié)點(diǎn)。
優(yōu)點(diǎn):
- 簡化了客戶端代碼,客戶端可以統(tǒng)一處理組合結(jié)構(gòu)和對(duì)象。
- 更好的層次結(jié)構(gòu)表示,易于擴(kuò)展和維護(hù)。
缺點(diǎn):
- 設(shè)計(jì)較復(fù)雜,需要合理地設(shè)計(jì)組件的接口和類。
應(yīng)用場景:
- 文件系統(tǒng):文件系統(tǒng)中的文件和文件夾可以形成樹狀結(jié)構(gòu),其中文件夾可以包含文件和其他文件夾。
- 組織結(jié)構(gòu):公司的組織結(jié)構(gòu)可以表示為樹狀結(jié)構(gòu),其中每個(gè)部門可以包含員工和其他子部門。
- GUI組件:在圖形用戶界面開發(fā)中,組件可以包含其他組件,形成復(fù)雜的界面結(jié)構(gòu)。
- 分布式系統(tǒng):在分布式系統(tǒng)中,資源可以組合成樹狀結(jié)構(gòu),以方便管理和訪問。
- 企業(yè)資源規(guī)劃(ERP):ERP系統(tǒng)中,產(chǎn)品可以由多個(gè)部件組成,部件又可以進(jìn)一步分解為子部件。
// 定義Component接口,作為組合中對(duì)象的一致性協(xié)議
type Component interface {
Operation() // 執(zhí)行操作的方法
Add(Component) // 向組合中添加子節(jié)點(diǎn)的方法
Remove(Component) // 從組合中移除子節(jié)點(diǎn)的方法
GetChild(int) Component // 根據(jù)索引獲取子節(jié)點(diǎn)的方法
}
// 定義Leaf結(jié)構(gòu)體,表示組合中的葉節(jié)點(diǎn)
type Leaf struct {
name string
}
// Leaf實(shí)現(xiàn)Component接口的Operation方法
func (l *Leaf) Operation() {
fmt.Println("Leaf:", l.name)
}
// Leaf實(shí)現(xiàn)Component接口的Add方法,葉節(jié)點(diǎn)不能有子節(jié)點(diǎn),因此這里可以不實(shí)現(xiàn)或拋出錯(cuò)誤
func (l *Leaf) Add(c Component) {
fmt.Println("Cannot add to a leaf")
}
// Leaf實(shí)現(xiàn)Component接口的Remove方法,葉節(jié)點(diǎn)不能有子節(jié)點(diǎn),因此這里可以不實(shí)現(xiàn)或拋出錯(cuò)誤
func (l *Leaf) Remove(c Component) {
fmt.Println("Cannot remove from a leaf")
}
// Leaf實(shí)現(xiàn)Component接口的GetChild方法,葉節(jié)點(diǎn)沒有子節(jié)點(diǎn),因此這里返回nil
func (l *Leaf) GetChild(i int) Component {
return nil
}
// 定義Composite結(jié)構(gòu)體,表示組合中的容器節(jié)點(diǎn)
type Composite struct {
name string
Children []Component // 存儲(chǔ)子節(jié)點(diǎn)的列表
}
// Composite實(shí)現(xiàn)Component接口的Operation方法
func (c *Composite) Operation() {
fmt.Println("Composite:", c.name)
for _, child := range c.Children {
child.Operation() // 遞歸調(diào)用子節(jié)點(diǎn)的Operation方法
}
}
// Composite實(shí)現(xiàn)Component接口的Add方法,向Children列表中添加子節(jié)點(diǎn)
func (c *Composite) Add(component Component) {
c.Children = append(c.Children, component)
}
// Composite實(shí)現(xiàn)Component接口的Remove方法,從Children列表中移除子節(jié)點(diǎn)
func (c *Composite) Remove(component Component) {
for i, child := range c.Children {
if child == component {
c.Children = append(c.Children[:i], c.Children[i+1:]...)
break
}
}
}
// Composite實(shí)現(xiàn)Component接口的GetChild方法,根據(jù)索引獲取子節(jié)點(diǎn)
func (c *Composite) GetChild(i int) Component {
if i < 0 || i >= len(c.Children) {
return nil // 索引超出范圍,返回nil
}
return c.Children[i]
}
func main() {
// 創(chuàng)建葉節(jié)點(diǎn)
leafA := &Leaf{name: "Leaf A"}
leafB := &Leaf{name: "Leaf B"}
// 創(chuàng)建組合節(jié)點(diǎn)
composite := &Composite{name: "Composite Root"}
composite.Add(leafA) // 向組合中添加葉節(jié)點(diǎn)A
composite.Add(leafB) // 向組合中添加葉節(jié)點(diǎn)B
// 執(zhí)行組合節(jié)點(diǎn)的操作
composite.Operation()
}
10. 迭代器模式(Iterator Pattern)
迭代器模式是一種行為設(shè)計(jì)模式,它允許你順序訪問一個(gè)聚合對(duì)象中的各個(gè)元素而不需要暴露其內(nèi)部的表示。迭代器模式提供了一種通過抽象迭代器來遍歷元素的方法,使得你可以在不知道具體集合類型的情況下,對(duì)集合進(jìn)行遍歷。
特點(diǎn):
- 抽象化遍歷過程:迭代器定義了遍歷元素的接口。
- 支持多種遍歷方式:不同的迭代器可以實(shí)現(xiàn)不同的遍歷策略。
- 聚合對(duì)象與迭代器解耦:聚合對(duì)象不需要知道迭代器的具體實(shí)現(xiàn)。
優(yōu)點(diǎn):
- 抽象化集合的訪問,使客戶端代碼與集合的內(nèi)部表示無關(guān)。
- 可以提供多種遍歷方式,如正序或逆序遍歷。
- 增加了集合的靈活性,可以在不修改集合類的情況下,引入新的遍歷方式。
缺點(diǎn):
- 增加了系統(tǒng)的復(fù)雜性,需要為每個(gè)聚合類設(shè)計(jì)迭代器類。
- 需要額外的代碼來實(shí)現(xiàn)迭代器。
應(yīng)用場景:
- 遍歷集合:在需要遍歷集合元素的系統(tǒng)中,迭代器模式提供了一種通用的遍歷機(jī)制。
- 數(shù)據(jù)結(jié)構(gòu):在實(shí)現(xiàn)復(fù)雜的數(shù)據(jù)結(jié)構(gòu)如樹、圖等時(shí),迭代器模式可以用來遍歷結(jié)構(gòu)中的節(jié)點(diǎn)。
- 數(shù)據(jù)庫查詢:在數(shù)據(jù)庫查詢中,迭代器可以用來逐條訪問查詢結(jié)果。
- 用戶界面:在用戶界面開發(fā)中,迭代器可以用來遍歷界面元素。
- 多維數(shù)組訪問:在需要訪問多維數(shù)組元素的系統(tǒng)中,迭代器可以提供一種順序訪問的方式。
// 定義Iterator接口,它聲明了迭代器必須實(shí)現(xiàn)的Next和Current方法
type Iterator interface {
Next() bool // 移動(dòng)到下一個(gè)元素,并返回是否成功移動(dòng)
Current() interface{} // 返回當(dāng)前元素
}
// 定義ConcreteIterator結(jié)構(gòu)體,它實(shí)現(xiàn)了Iterator接口
type ConcreteIterator struct {
items []string // 存儲(chǔ)聚合對(duì)象的元素列表
index int // 當(dāng)前迭代到的元素索引
}
// Next方法實(shí)現(xiàn),用于移動(dòng)到下一個(gè)元素
func (c *ConcreteIterator) Next() bool {
if c.index < len(c.items) {
c.index++ // 索引遞增
return true
}
return false // 如果索引超出范圍,返回false
}
// Current方法實(shí)現(xiàn),用于返回當(dāng)前元素
func (c *ConcreteIterator) Current() interface{} {
if c.index > 0 && c.index <= len(c.items) {
return c.items[c.index-1] // 返回當(dāng)前索引的元素
}
return nil // 如果索引不在范圍內(nèi),返回nil
}
// 定義Aggregate接口,表示聚合對(duì)象,它將負(fù)責(zé)創(chuàng)建迭代器
type Aggregate interface {
CreateIterator() Iterator // 創(chuàng)建并返回迭代器
}
// 定義ConcreteAggregate結(jié)構(gòu)體,它實(shí)現(xiàn)了Aggregate接口
type ConcreteAggregate struct {
items []string // 聚合對(duì)象存儲(chǔ)的元素列表
}
// CreateIterator方法實(shí)現(xiàn),用于創(chuàng)建并返回一個(gè)迭代器
func (a *ConcreteAggregate) CreateIterator() Iterator {
return &ConcreteIterator{items: a.items, index: 0} // 返回一個(gè)新的迭代器實(shí)例
}
func main() {
// 創(chuàng)建聚合對(duì)象并添加元素
aggregate := &ConcreteAggregate{items: []string{"Item1", "Item2", "Item3"}}
// 使用聚合對(duì)象創(chuàng)建迭代器
iterator := aggregate.CreateIterator()
// 使用迭代器遍歷聚合對(duì)象中的所有元素
for iterator.Next() {
fmt.Println(iterator.Current())
}
}