Golang Option 模式

Golang Option模式

1. 传统的结构体初始化方式

type Server struct {
	maxConn int
	id string
	tls bool
}

// NewServer 初始化Server
func NewServer(maxConn int, id string, tls bool) *Server {
	return &Server{
		maxConn: maxConn,
		id:      id,
		tls:     tls,
	}
}

func TestServer() {
	// 传入配置,初始化Server
	server := NewServer(1, "Sakura01", false)
}

这样做的问题在于,如果有一个库或者 Server 有更多的配置项,这样初始化机构体会变得非常繁琐

2. 稍微改进一下

// 创建一个ServerOps包含Server所有配置选项
type ServerOps struct {
	maxConn int
	id      string
	tls     bool
}

// 将ServerOps嵌入Server中
type Server struct {
	ServerOps
}

// NewServer 初始化Server的时候参数为ServerOps,也及时要传入结构体
func NewServer(serverOps ServerOps) *Server {
	return &Server{
		ServerOps: serverOps,
	}
}

func InitServer() {
	// 传入配置,初始化Server
	server := NewServer(ServerOps{})
	fmt.Println(server)
}

可以看到初始化 Server 更麻烦了,不过目前还没有配置完

3. 进一步改进

用户不一定要提供选项才能创建 Server,但是要提供能修改配置项的可能性

所以需要有一个默认配置项DefaultConfig

  1. 首先定义一个函数类型,函数接收一个指向 ServerOps 的指针
type ServerOpsFunc func(*ServerOps) 

// 定义的函数类型有两个使用方式
// 1.返回这个类型的函数
func Test(num int) ServerOpsFunc {
	return  func(ops *ServerOps) {
		ops.maxConn = NUm
	}
}

// 2.定义这种类型的函数
func withTls(ServeOps *ServerOps) {
	ServeOps.tls = true
}
  1. 然后创建一个默认配置项defaultServerOps 函数
func defaultServerOps() ServerOps {
	return ServerOps{
		maxConn: 10,
		id:      "dafault",
		tls:     false,
	}
}
  1. 将初始化 Server 构造器的接收参数改为接收任意个ServerOpsFunc 函数切片

这样可以使得用户在不提供任何选项的情况下初始化一个配置

// NewServer 初始化Server
func NewServer(serverOps ...ServerOpsFunc) *Server {
	defaultOps := defaultServerOps()
	// 如果提供了配置项,那么
	for _, fn := range serverOps {
		fn(&defaultOps)
	}
	return &Server{
		ServerOps: defaultOps,
	}
}
  1. 如果在NewServer 中提供了配置项,那么遍历参数列表,修改 defaultOps 的值
func withMaxConn(n int) ServerOpsFunc {
	return func(ops *ServerOps) {
		ops.maxConn = n
	}
}

func withId(id string) ServerOpsFunc {
	return func(ops *ServerOps) {
		ops.id = id
	}
}

// withTLs可以有两种写法,这两种写法都实现了自定义的函数类型
func withTls() ServerOpsFunc {
	return func(ops *ServerOps) {
		ops.tls = true
	}
}

func withTls(ServeOps *ServerOps) {
	ServeOps.tls = true
}

其中 wirhTls 有两种写法,既可以返回一个 ServerOpsFunc,也可以直接将函数定义为 SeverOpsFunc

func InitServer() {
    // 默认配置
    server := NewServer()
    fmt.Println("---------默认配置--------")
    fmt.Println(server)
    // 传入配置项
    serve1 := NewServer(withId("SakurasServer"), withMaxConn(999))
    fmt.Println("---------传入配置--------")
    fmt.Println(serve1)
    // withTLS的两种使用
    // func withTls() ServerOpsFunc
    serve2 := NewServer(withTls())
    fmt.Println("--------TLS配置--------")
    fmt.Println(serve2)
    // func withTls(ServeOps *ServerOps)
    // server4 := NewServer(withTls)
}

4. 完整代码

package Option

import (
	"fmt"
)

type ServerOpsFunc func(*ServerOps)

type ServerOps struct {
	maxConn int
	id      string
	tls     bool
}

func defaultServerOps() ServerOps {
	return ServerOps{
		maxConn: 10,
		id:      "dafault",
		tls:     false,
	}
}

type Server struct {
	ServerOps
}

func withMaxConn(n int) ServerOpsFunc {
	return func(ops *ServerOps) {
		ops.maxConn = n
	}
}

func withId(id string) ServerOpsFunc {
	return func(ops *ServerOps) {
		ops.id = id
	}
}

// withTLs可以有两种写法,这两种写法都实现了自定义的函数类型
func withTls() ServerOpsFunc {
	return func(ops *ServerOps) {
		ops.tls = true
	}
}
func withTls2(ServeOps *ServerOps) {
	ServeOps.tls = true
}

// NewServer 初始化Server
func NewServer(serverOps ...ServerOpsFunc) *Server {
	defaultOps := defaultServerOps()
	// 如果提供了配置项,那么挨个比那里修改默认配置
	// 因为切片是函数类型的,所以fn为函数
	// 这里不明白的可以debug一下
	for _, fn := range serverOps {
		fn(&defaultOps)
	}
	return &Server{
		ServerOps: defaultOps,
	}
}

func InitServer() {
	// 默认配置
	server := NewServer()
	fmt.Println(server)

	// 自定义配置
	server1 := NewServer(withId("Sakura"), withMaxConn(1000))
	fmt.Println(server1)
}

可以看到自定义配置中,没有提供的配置项,用的还是默认配置
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值