编程中,需要对一个对象(或是业务实体)进行相关的配置
1)
import (
"crypto/tls"
"time"
)
type Server struct{
Addr string
Port int
Protocol string
Timeout time.Duration
MaxConnects int
TLS *tls.Config
}
func NewDefaultServer(addr string, port int) (*Server, error) {
return &Server{addr, port, "tcp", 30 * time.Second, 100, nil}, nil
}
func NewTLSServer(addr string, port int, tls *tls.Config) (*Server, error) {
return &Server{addr, port, "tcp", 30 * time.Second, 100, tls}, nil
}
func NewServerWithTimeout(addr string, port int, timeout time.Duration) (*Server, error) {
return &Server{addr, port, "tcp", timeout, 100, nil}, nil
}
func NewTLSServerWithMaxConnAndTimeout(addr string, port int, maxconns int, timeout time.Duration, tls *tls.Config) (*Server, error) {
return &Server{addr, port, "tcp", 30 * time.Second, maxconns, tls}, nil
}
对于上述这样的配置,我们需要有多种不同的创建不同配置 Server 的函数签名
Go语言不支持重载函数
,得用不同的函数名来应对不同的配置选项
2) 结构体嵌入 (把非必要的config 独立出来)
package main_test
import (
"crypto/tls"
"testing"
"time"
)
type Server struct{
Addr string
Port int
Conf *Config
}
type Config struct {
Protocol string
Timeout time.Duration
MaxConnects int
TLS *tls.Config
}
func NewServer(addr string, port int, conf *Config)(*Server, error){
return &Server{addr, port, conf}, nil
}
func TestServer(t *testing.T){
srv1, _ := NewServer("localhost", 9001, nil)
conf := Config{
"tcp",
30 * time.Second,
30,
nil,
}
srv2, _ := NewServer("localhost", 9001, &conf)
t.Log(srv1)
t.Log(srv2)
}
Builder模式
链式的函数调用的方式来构造一个对象,只需要多加一个Builder类,这个Builder类似乎有点多余,我们似乎可以直接在Server 上进行这样的 Builder 构造
3) Builder 模式
package main_test
import (
"crypto/tls"
"testing"
"time"
)
type Server struct {
Addr string
Port int
Protocol string
Timeout time.Duration
MaxConnects int
TLS *tls.Config
}
type ServerBuilder struct {
Server
}
func (sb *ServerBuilder) Create(addr string, port int) *ServerBuilder {
sb.Server.Addr = addr
sb.Server.Port = port
return sb
}
func (sb *ServerBuilder) WithProtocol(protocol string) *ServerBuilder{
sb.Server.Protocol = protocol
return sb
}
func (sb *ServerBuilder) WithMaxConnects(maxconns int) *ServerBuilder{
sb.Server.MaxConnects = maxconns
return sb
}
func (sb *ServerBuilder) WithTimeOut( timeout time.Duration) *ServerBuilder {
sb.Server.Timeout = timeout
return sb
}
func (sb *ServerBuilder) WithTLS( tls *tls.Config) *ServerBuilder {
sb.Server.TLS = tls
return sb
}
func (sb *ServerBuilder) Build() (*Server, error){
return &sb.Server, nil
}
func TestBuilder(t *testing.T){
sb := ServerBuilder{}
server, err := sb.Create("127.0.0.1", 8080).
WithProtocol("udp").
WithMaxConnects(1024).
WithTimeOut(30*time.Second).
Build()
t.Log(server, err)
}
Functional Options, 使用闭包
//可以使用默认值, 只需要传非默认值以外的值
4) 函数式选项模式
package main_test
import (
"crypto/tls"
"testing"
"time"
)
type Server struct {
Addr string
Port int
Protocol string
Timeout time.Duration
MaxConnects int
TLS *tls.Config
}
type Option func(server *Server)
func Protocol(p string) Option{
return func(s *Server){
s.Protocol = p
}
}
func Timeout(timeout time.Duration) Option {
return func(s *Server){
s.Timeout = timeout
}
}
func MaxConns(maxconns int) Option {
return func(s *Server) {
s.MaxConnects = maxconns
}
}
func TLS(tls *tls.Config) Option {
return func(s *Server) {
s.TLS = tls
}
}
func NewServer(addr string, port int, options ...func(server *Server)) (*Server, error) {
srv := Server{
Addr: addr,
Port: port,
Protocol: "tcp",
Timeout: 30 * time.Second,
MaxConnects: 1000,
TLS: nil,
}
for _, options := range options{
options(&srv)
}
return &srv, nil
}
func TestOptionFunc(t *testing.T){
s1, _ := NewServer("localhost", 1024)
s2, _ := NewServer("localhost", 1024, Protocol("udp"))
s3, _ := NewServer("localhost", 1024, Protocol("udp"),Timeout(300*time.Second), MaxConns(1000))
s4, _ := NewServer("localhost", 1024, TLS(nil))
t.Log(s1, s2, s3, s4)
}