天天看点

Go 设计模式-建造者模式

设计模式

Go 设计模式-建造者模式

建造者模式

工厂模式用来创建不同、但是类型相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定哪种类型的对象,建造者模式是用来构建一种复杂对象,可以通过设置不同的可选参数,定制化创建不同的对象,

应用场景

  • 把类的必填属性放在构造函数中,强制创建的时候设置,如果必填属性很多,这些必填属性都需要放到构造函数中设置,那构造函数就会出现参数列表很长的问题。如果我们把必填属性通过 set() 方法设置,那校验这些属性是否填写的逻辑又无处安放。
  • 如果类属性之间有一定的依赖关系或者约束条件,我们继续用构造函数配合 set() 方法设计思路,那这些依赖关系或者约束条件又无处安放。
  • 如果我们希望创建不可变对象,也就是说,对象在创建好之后,就不能再修改内部的属性值,要实现这个功能,就不能暴露 set 方法,构造函数配合 set() 方法就不合适了。

代码例子

builder.go

package builder

//Builder 生成器接口
type Builder interface {
 Part1()
 Part2()
 Part3()
}

type Director struct {
 builder Builder
}

// NewDirector ...
func NewDirector(builder Builder) *Director {
 return &Director{
  builder: builder,
 }
}

//Construct Product
func (d *Director) Construct() {
 d.builder.Part1()
 d.builder.Part2()
 d.builder.Part3()
}

type Builder1 struct {
 result string
}

func (b *Builder1) Part1() {
 b.result += "1"
}

func (b *Builder1) Part2() {
 b.result += "2"
}

func (b *Builder1) Part3() {
 b.result += "3"
}

func (b *Builder1) GetResult() string {
 return b.result
}

type Builder2 struct {
 result int
}

func (b *Builder2) Part1() {
 b.result += 1
}

func (b *Builder2) Part2() {
 b.result += 2
}

func (b *Builder2) Part3() {
 b.result += 3
}

func (b *Builder2) GetResult() int {
 return b.result
}
           

复制

builder_test.go

package builder

import "testing"

func TestBuilder1(t *testing.T) {
 builder := &Builder1{}
 director := NewDirector(builder)
 director.Construct()
 res := builder.GetResult()
 if res != "123" {
  t.Fatalf("Builder1 fail expect 123 acture %s", res)
 }
}

func TestBuilder2(t *testing.T) {
 builder := &Builder2{}
 director := NewDirector(builder)
 director.Construct()
 res := builder.GetResult()
 if res != 6 {
  t.Fatalf("Builder2 fail expect 6 acture %d", res)
 }
}
           

复制

再看个例子

type Options struct {
 ConnTimeout time.Duration
 ReadTimeout time.Duration
 RetryTime   int32
}

// builder 模式
func (opt *Options) build() (err error) {
 // 校验逻辑
 if opt.ReadTimeout < opt.ConnTimeout {
  err = errors.New("error params")
  return
 }
 return
}
// 设置属性 ConnTimeOut
func (opt *Options) setConnTimeout(timeout time.Duration) *Options {
 opt.ConnTimeout = timeout
 return opt
}
// 设置属性 ReadTimeOut
func (opt *Options) setReadTimeout(timeout time.Duration) *Options {
 opt.ReadTimeout = timeout
 return opt
}
// 设置属性 retryTime
func (opt *Options) setRetryTime(times int32) *Options {
 opt.RetryTime = times
 return opt
}
           

复制

builder_test.go

package main

import "testing"

func Build() {
 opt := &Options{}
 err := opt.
  setConnTimeout(100 * time.Second).
  setReadTimeout(1000 * time.Second).
  setRetryTime(1).
  build()
 if err != nil {
  panic(err)
 }
 fmt.Printf("BuildV1: %+v\n", opt)
}

func TestAppDemo(t *testing.T) {
 Build()
}

           

复制

参考资料

  • https://github.com/senghoo/golang-design-pattern