13 Dec 2022
想象我们有一个结构体
type Person struct { Name string Age int Job string Title string Religion string Hobby string }
其中:
Name和Age是必传的参数Job和Title是工作相关的选填参数,Religion是宗教信息相关的选填参数,Hobby是可有可无的选填参数。这些选填参数都会有默认值。在这种情况下,当我们创建一个新的对象时,根据不同的情况,我们需要使用不同的参数来创建
func NewPerson(name string, age int8) *Person { return &Person{Name: name, Age: age} } func NewBoss(name string, age int8, hobby string) *Person { return &Person{Name: name, Age: age, Hobby: hobby} } func NewWorker(name string, age int8, job string, religion string) *Person { return &Person{Name: name, Age: age, Job: job, Religion: religion} }
为了解决上面的问题,我们可以使用builder模式
type Person struct { Name string Age int8 Job string Title string Religion string Hobby string } type PersonBuilder struct { Person } func (pb *PersonBuilder) NewPerson(name string, age int8) *PersonBuilder { pb.Person.Name = name pb.Person.Age = age return pb } func (pb *PersonBuilder) WithJob(job string, title string) *PersonBuilder { pb.Person.Job = job pb.Person.Title = title return pb } func (pb *PersonBuilder) WithReligion(religion string) *PersonBuilder { pb.Person.Religion = religion return pb } func (pb *PersonBuilder) WithHobby(hobby string) *PersonBuilder { pb.Person.Hobby = hobby return pb } func (pb *PersonBuilder) Build() Person { return pb.Person }
这样,我们就可以这样使用。
pb := PersonBuilder{} person := pb.NewPerson("Tom", 18). WithJob("boss", "CEO"). Build()
但是这里多了一个Builder类,只是为了解决一个参数的问题,好像有点大材小用了。在纯解决参数传入问题的场景下,如果我们想省掉这个Builder类,就可以使用Functional Options了
我们可以定义一个函数类型,这个函数只接收struct的指针。
type PersonOption func(*Person) func WithJob(job string, title string) PersonOption { return func(person *Person) { person.Job = job person.Title = title } } func WithReligion(religion string) PersonOption { return func(person *Person) { person.Religion = religion } } func WithHobby(hobby string) PersonOption { return func(person *Person) { person.Hobby = hobby } }
然后我们改造创建struct的函数
func NewPerson(name string, age int8, opts ...PersonOption) *Person { p := &Person{ Name: name, Age: age, } for _, opt := range opts { opt(p) } return p }
后面我们就可以使用这种方式来创建struct
nobody := NewPerson("Tom", 18) boss := NewPerson("Bill", 23, WithJob("boss", "CEO"), WithHobby("beauty")) woker := NewPerson("John", 32, WithJob("farmer", "senior"), WithHobby("study"),WithReligion("Money"))
这样的方式,简洁明了,高内聚,符合直觉,理解简单