2. 裝飾器模式
裝飾器模式,動態地給一個對象添加一些額外的職責,就增加功能來說,裝飾器模式比生成子類更加靈活。它把每個要裝飾的功能放在單獨的類中,並讓這個類包裝它所要裝飾的對象,在使用時要注意裝飾的順序。
比如我們想給核心代碼添加日志打印功能,但是又不能改動原有代碼,可以使用裝飾器模式來包裝原有的代碼。
在路徑decorator\
下新建文件decorator.go
,包名為decorator
:
package decorator
// ...
如下為工作代碼:
// 工作代碼
func Work() {
fmt.Println("工作中...")
time.Sleep(time.Second)
}
定義一個裝飾器函數來包裝工作代碼:
// logger函數包裝工作代碼
func Logger(f func()) {
now := time.Now()
fmt.Printf("開始:%v\n", now.Format("2006-01-02 15:04:05.000"))
f() // 工作代碼
end := time.Now()
fmt.Printf("結束:%v\n", end.Format("2006-01-02 15:04:05.000"))
fmt.Printf("耗時:%v\n", end.Sub(now))
}
加入工作代碼的函數簽名與Logger()函數的參數不匹配,這時候可以使用橋接模式定義一個橋接函數,來把2個函數橋接起來:
// 工作代碼——需要接受參數
func WorkWithArgs(name string) {
fmt.Printf("%s——工作中...", name)
time.Sleep(time.Second * 2)
}
// 工作方法與裝飾器不匹配,用中間方法進行橋接
func Bridge(f func(string), name string) func() {
return func() {
f(name)
}
}
在路徑decorator
的同級目錄下新建main.go
用於測試方法:
package main
import (
"fmt"
"github.com/loveshes/go-design-patterns/pattern/decorator-pattern/decorator"
)
func main() {
work := decorator.Work
// 直接調用work()
work()
fmt.Println()
// 使用裝飾器調用work()
decorator.Logger(work)
fmt.Println()
// 橋接方法
work2 := decorator.WorkWithArgs
bridge := decorator.Bridge
decorator.Logger(bridge(work2, "[工作方法]"))
}
輸出為
工作中...
開始:2020-04-19 23:08:36.317
工作中...
結束:2020-04-19 23:08:37.336
耗時:1.0190352s
開始:2020-04-19 23:08:37.336
[工作方法]——工作中...結束:2020-04-19 23:08:39.337
耗時:2.0000624s