Go语言之装饰器

 

GitHub - robfig/cron: a cron library for go https://github.com/robfig/cron/

 

// JobWrapper decorates the given Job with some behavior.
type JobWrapper func(Job) Job

// Chain is a sequence of JobWrappers that decorates submitted jobs with
// cross-cutting behaviors like logging or synchronization.
type Chain struct {
    wrappers []JobWrapper
}

 

 

Go语言之装饰器 - lxsky - 博客园 https://www.cnblogs.com/lxsky/p/12050217.html

【Golang设计模式】2.装饰器模式 - 杨柳依 - 博客园 https://www.cnblogs.com/loveshes/p/12734970.html

 

Go的装饰器本质上允许您包装现有功能,并添加你自己的自定义功能,它操作的对象是函数,返回的对象也是函数。
1.简单的一个装饰器例子:

结果分析:从输出的结果能够看出,调用了装饰器之后,函数testFunc已经实现了,“自己的代码 + 原来代码”的效果。

2.如果我们希望装饰器装饰的函数类型不是固定的呢,也就是说我们希望装饰器装饰的函数可以是任何函数,这样我们该怎么办?

答案:采用空interface,因为Go语言中空interface是泛型的基础。

例子如下所示:

结果分析:Go中空interface的存在,使得泛型的实现成了可能,实现一个装饰器函数就可以支持多种类型的函数。通过测试结果可以看出来,这个功能确实工作了,而注释中的1,2,3,4是对装饰器实现的介绍,对与装饰器自己的代码那一部分,你可以按照自己的希望来定制实现。

3.如果同一个函数,我们希望采用不同的装饰器来分别装饰它的话,该怎么办呢?

最简单的做法就是分别实现多个装饰器函数,然后依次顺序调用这些装饰器函数, 例子如下:

对于上面的代码,在装饰器不是很多的时候,还可以忍受,等装饰器很多的时候,就会显得很不好看,为了让他们变得优雅一些,我们优化成下面的样子。
结果分析:通过结果输出能看出来,两种方法实现的效果是一样的,第二种明显会更加优雅一些。

 

【Golang设计模式】2.装饰器模式

 

2. 装饰器模式

装饰器模式,动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更加灵活。它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,在使用时要注意装饰的顺序。

比如我们想给核心代码添加日志打印功能,但是又不能改动原有代码,可以使用装饰器模式来包装原有的代码。

在路径decorator\下新建文件decorator.go,包名为decorator

Copy
package decorator

// ...

如下为工作代码:

Copy
// 工作代码
func Work() {
	fmt.Println("工作中...")
	time.Sleep(time.Second)
}

定义一个装饰器函数来包装工作代码:

Copy
// 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个函数桥接起来:

Copy
// 工作代码——需要接受参数
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用于测试方法:

Copy
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, "[工作方法]"))
}

输出为

Copy
工作中...

开始: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

 

posted @ 2022-02-21 09:47  papering  阅读(115)  评论(0编辑  收藏  举报