Go语言的Functional Options模式

562 阅读1分钟

在编程中,我们经常需要对一个对象进行相关的配置。比如新增员工,我们需要填写姓名、年龄、邮箱等;但是对于座机、性别可能就不是必填选项,如下代码示例:

type User struct {
   Name   string
   Age    int
   Email  string
   Phone  string
   //...Other
   School string
   Gender string
}

在其他面向对象的语言中,如Java,我们可以通过重载函数解决初始化参数问题。因为 Go 语言不支持重载函数,所以,你得用不同的函数名来应对不同的配置选项。

func NewDefaultUser(name string, age int, email string) (*User, error) {
   return &User{Name: name, Age: age, Email: email}, nil
}

func NewPhoneUser(name string, age int, email string, phone string) (*Server, error) {
   return &User{Name: name, Age: age, Email: email, Phone: phone}, nil
}

Builder 模式

Java 程序员,一定会很自然地使用 Builder 模式。

User user = new User.Builder()
  .name("Moonus")
  .email("moonus@outlook.com")
  .age(18)
  .build();

Functional Options

// UserOption 我们定义一个函数类型,类似C#与委托函数Action
type UserOption func(*User)

然后,我们可以使用函数式的方式定义一组如下的函数:

func Phone(phone string) UserOption {
   return func(user *User) {
      user.Phone = phone
   }
}

func School(school string) UserOption {
   return func(user *User) {
      user.School = school
   }
}

func Gender(gender string) UserOption {
   return func(user *User) {
      user.Gender = gender
   }
}

通过可变参数 options,for-loop 来设置我们的 User 对象。

func CreateUser(name string, age int, email string, opt ...UserOption) User {
   user := User{Name: name, Age: age, Email: email}

   for _, option := range opt {
      option(&user)
   }
   return user
}
func TestUser(t *testing.T) {
   user := CreateUser("Moonus", 18, "Moonus@outlook.com", Phone("110"), func(user2 *User) {
      user2.Gender = "男"
   })
   fmt.Println(user)
}

Functional Options通过函数式,可以帮助开发者更加灵活得初始化对象,易于扩展。比如初始化对象我们需要设置默认值,通过该设计能快速解决该问题。