设计模式
建造者模式
工厂模式用来创建不同、但是类型相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定哪种类型的对象,建造者模式是用来构建一种复杂对象,可以通过设置不同的可选参数,定制化创建不同的对象,
应用场景
- 把类的必填属性放在构造函数中,强制创建的时候设置,如果必填属性很多,这些必填属性都需要放到构造函数中设置,那构造函数就会出现参数列表很长的问题。如果我们把必填属性通过 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() }