思考(五十五):Golang 编程之装饰器模式

装饰器模式

装饰器模式:允许向一个现有的对象添加新的功能,同时又不改变其结构

C++ 中典型例子是继承+多态,可以自己百度下

这里介绍 golang 实际项目中用到的,达到装饰器模式同样效果的例子

摘自作者自己的描述是:

It’s a design pattern that allows the addition of new options without changing the method signature.

该例子来至: github.com/micro/go-micro

实际效果

func main() {
	// 装饰器模式在这里:
	//   micro.NewService 定义接口保持不变
	//   可以接受任意数量`选项对象`,达成设置、打开各种功能,或其他初始化操作
	service := micro.NewService(
		micro.Name("com.example.srv.foo"),           // 这是个`选项对象`
		micro.RegisterTTL(time.Second*30),           // 这是个`选项对象`
		micro.RegisterInterval(time.Second*15),      // 这是个`选项对象`
	)
	service.Init()
	if err := service.Run(); err != nil {
		log.Fatal(err)
	}
}

实现细节

相关代码主要分布在:

实现细节摘录如下:

type Option func(*Options)                        // `选项对象`实际类型为函数, 这是重点
func NewService(opts ...Option) Service {         // 接口保持不变,类似 AddOption 其实也可以,没这个简洁
	return newService(opts...)
}
func newService(opts ...Option) Service {
	options := newOptions(opts...)
	// ... 无关代码略 ...
	return &service{
		opts: options,
	}
}
func newOptions(opts ...Option) Options {
	// 初始化 opt 对象,设置初始值
	opt := Options{
		Broker:    broker.DefaultBroker,
		Cmd:       cmd.DefaultCmd,
		Client:    client.DefaultClient,
		Server:    server.DefaultServer,
		Registry:  registry.DefaultRegistry,
		Transport: transport.DefaultTransport,
		Context:   context.Background(),
	}

	// 这里是重点,`选项对象`在这里生效
	for _, o := range opts {
		o(&opt)
	}
	
	return opt
}
// 具体某个`选项对象`
func Name(n string) Option {
    // 返回函数对象
	return func(o *Options) {
		o.Server.Init(server.Name(n))
	}
}

代码分析

1. Option 类型

Option 是个函数对象类型

这样自由度很大,函数体内可以实现你的意图,比如 Name 这个 Option :

func Name(n string) Option {
	return func(o *Options) {
		o.Server.Init(server.Name(n))
	}
}

Name 这个 Option , 实现对 o.Server 对象初始化时,赋值名字

2. NewService(opts …Option) 接口定义

这样的接口定义,即参数可变,又保持接口定义不变

比如 AddOption(opt Option) 本质上也是可以的,但没 NewService 接口简洁

3. Option 函数对象生效代码
for _, o := range opts {
	o(&opt)
}

opt 保持着所有需要初始化的对象,opts 内是所有 Option 对象

上述语句,让所有 Option 对象实实在在作用于 opt 上

关于生效时机,看上述代码在什么函数调用,比如 NewService 中调用,即构造对象时生效

也可以在诸如 Init() 这种函数内调用

Option 实现的优缺点

  • 优点
    • 使用界面相当简洁
    • 用法优美
  • 缺点
    • 实现细节稍繁琐
    • 每个 Option 对象要写段函数

以上

发布了129 篇原创文章 · 获赞 73 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/u013272009/article/details/92844321