golang建造者模式-函数式选项模式

576 阅读2分钟

建造者模式也叫生成器模式/builder,是一种创建型模式,可以分步骤创建复杂对象,比较经典的就是 sql 生成器了。因为语言的特性,golang 可以用函数式选项模式来实现,也是项目中比较流行的方式。

传统实现

以 实例化资源配置池 为例:

定义builder的接口

package main

// 假设数据库的配置项
type IBuilder interface {
	SetMaxTotal(int) IBuilder // 最大链接数
	SetMaxIdle(int) IBuilder  // 最大空闲链接数
	SetMinIdle(int) IBuilder  // 最小空闲链接数
}

具体实现

  • 略去具体细节
package main

type server struct {
	addr     string
	port     string
	maxTotal int
	maxIdle  int
	minIdle  int
}

// 外面包装一层构建器
type ServerBuild struct {
	server
}

func (m *ServerBuild) Create(addr string, port string) *ServerBuild {
	m.addr = addr
	m.port = port
	return m
}

func (m *ServerBuild) SetMaxTotal(n int) *ServerBuild {
	m.maxTotal = n
	return m
}

func (m *ServerBuild) SetMaxIdle(n int) *ServerBuild {
	m.maxIdle = n
	return m
}

func (m *ServerBuild) SetMinIdle(n int) *ServerBuild {
	m.minIdle = n
	return m
}

func (m *ServerBuild) Build() (server, error) {
	// 判断各个属性,
	return m.server, nil
}

客户端调用

package main

func client() {
	s := new(ServerBuild)
	
	server, err := s.Create("127.0.0.1", "9527").
	SetMaxTotal(100).
	SetMinIdle(20).
	Build()
}

如果参数比较少,可以直接构建的时候传递进函数。但参数过多,而且都是可选项时,放在同一个函数中传惨就会变得不清晰明了,而且,如果各参数之间有相互依赖关系时,放在同一个构造函数中,代码的可读性和可维护性都会变差,通过建造者模式分步构建,就好多了。

函数式选项(option模式)实现

利用golang语言闭包的特性,给server各属性赋值。

定义server

package main

// 函数式选项模式 还是以server 为例
type Server struct {
	Addr     string
	Port     string
	MaxTotal int
	MaxIdle  int
	MinIdle  int
}
// 选项函数
type option func(*Server)

各选项函数

package main

func SetMaxTotal(maxTotal int) func(*Server) {
	return func(s *Server) {
		s.MaxTotal = maxTotal
	}
}

func SetMaxIdle(maxIdle int) func(*Server) {
	return func(s *Server) {
		s.MaxIdle = maxIdle
	}
}

func SetMinIdle(minIdle int) func(*Server) {
	return func(s *Server) {
		s.MinIdle = minIdle
	}
}


创建server

package main

// 创建server
func NewServer(addr, port string, ops ...option) (*Server, error) {
	s := &Server{
		Addr: addr,
		Port: port,
	}
	for _, o := range ops {
		o(s)
	}
	return s, nil
}

客户端调用

package main

func client() {
	//方式一
	s1, _ := NewServer("127.0.0.1", "9527")

	// 方式二
	ops := []option{SetMaxIdle(20), SetMaxTotal(100)}
	s2, _ := NewServer("127.0.0.1", "9527", ops...)
}

总结

如果需要创建的各形式的产品,他们制造过程相似,只是细节上的差异,可以使用建造者模式。建造者模式关注的场景是某一个单一类的分步骤创建或不同选项创建。