Go一些tips

编程中,需要对一个对象(或是业务实体)进行相关的配置


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)
}



转自酷 壳 – COOLSHELL

Buy me a 肥仔水!