Heim  >  Artikel  >  Backend-Entwicklung  >  Ein Programmiermodell, das in vielen Go-Projekten aktiv ist

Ein Programmiermodell, das in vielen Go-Projekten aktiv ist

Go语言进阶学习
Go语言进阶学习nach vorne
2023-07-24 14:58:231335Durchsuche
Heute stellen wir ein sehr beliebtes Programmiermuster in der Go-Sprache vor: Funktionsoptionen. Das durch dieses Muster gelöste Problem besteht darin, Parameter für Objekte dynamischer und flexibler zu konfigurieren. Vielleicht verstehen die Leser diesen Schmerzpunkt nicht ganz, keine Sorge, wir werden ihn weiter unten im Detail erklären.

Frage

Angenommen, wir definieren im Code ein Benutzerstrukturobjekt User, das die folgenden Eigenschaften hat.

type User struct {
 ID      string    // 必需项
 Name    string    // 必需项
 Age     int       // 非必需项
 Gender  bool      // 非必需项
}

Beim Initialisieren des Objekts besteht die einfachste Möglichkeit darin, die Attributwerte direkt einzugeben, z. B.

u := &User{ID: "12glkui234d", Name: "菜刀", Age: 18, Gender: true}

Es gibt jedoch ein Problem: Die Attribute im Benutzerobjekt sind nicht unbedingt exportierbar hat ein Das Attributfeld ist ein Passwort (der erste Buchstabe ist ein Kleinbuchstabe und wird nicht exportiert). Wenn das Benutzerobjekt in anderen Modulen erstellt werden muss, kann das Passwortfeld nicht ausgefüllt werden.

Wir müssen also eine Funktion zum Erstellen des Benutzerobjekts definieren. Die einfachste Konstruktormethode, die man sich vorstellen kann, ist wie folgt.

func NewUser(id, name string, age int, gender bool) *User {
 return &User{
  ID:     id,
  Name:   name,
  Age:    age,
  Gender: gender,
 }
}

Aber es gibt auch einige Probleme: Für das Benutzerobjekt sind nur die Attribute „ID“ und „Name“ erforderlich, Alter und Geschlecht sind optional und der Standardwert für „Alter“ kann beispielsweise nicht festgelegt werden . Der Standardwert für Geschlecht ist falsch, was offensichtlich unangemessen ist.

Welche Lösungen können wir angesichts dieses Problems anwenden?

Option 1: Multifunktionskonstruktion

Die gröbste Lösung, die wir uns vorstellen können, besteht darin, für jede Parametersituation einen Konstruktor festzulegen. Wie im folgenden Code gezeigt

func NewUser(id, name string) *User {
 return &User{ID: id, Name: name}
}

func NewUserWithAge(id, name string, age int) *User {
 return &User{ID: id, Name: name, Age: age}
}

func NewUserWithGender(id, name string, gender bool) *User {
 return &User{ID: id, Name: name, Gender: gender}
}

func NewUserWithAgeGender(id, name string, age int, gender bool) *User {
 return &User{ID: id, Name: name, Age: age, Gender: gender}
}

这种方式适合参数较少且不易发生变化的情况。该方式在 Go 标准库中也有使用,例如 net 包中的 Dial 和 DialTimeout 方法。

func Dial(network, address string) (Conn, error) {}
func DialTimeout(network, address string, timeout time.Duration) (Conn, error) {}

但该方式的缺陷也很明显:试想,如果构造对象 User 增加了参数字段 Phone,那么我们需要新增多少个组合函数?

方案二:配置化

另外一种常见的方式是配置化,我们将所有可选的参数放入一个 Config 的配置结构体中。

type User struct {
 ID   string
 Name string
 Cfg  *Config
}

type Config struct {
 Age    int
 Gender bool
}

func NewUser(id, name string, cfg *Config) *User {
 return &User{ID: id, Name: name, Cfg: cfg}
}

这样,我们只需要一个 NewUser()  函数,不管之后增加多少配置选项,NewUser 函数都不会得到破坏。

但是,这种方式,我们需要先构造 Config 对象,这时候对 Config 的构造又回到了方案一中存在的问题。

方案三:函数式选项模式

面对这样的问题,我们还可以选择函数式选项模式。

首先,我们定义一个 Option 函数类型

type Option func(*User)

然后,为每个属性值定义一个返回 Option 函数的函数

func WithAge(age int) Option {
 return func(u *User) {
  u.Age = age
 }
}

func WithGender(gender bool) Option {
 return func(u *User) {
  u.Gender = gender
 }
}

此时,我们将 User 对象的构造函数改为如下所示

func NewUser(id, name string, options ...Option) *User {
 u := &User{ID: id, Name: name}
 for _, option := range options {
  option(u)
 }
 return u
}

按照这种构造方式,我们就可以这样配置 User 对象了

u := NewUser("12glkui234d", "菜刀", WithAge(18), WithGender(true))

以后不管 User 增加任何参数 XXX,我们只需要增加对应的 WithXXX 函数即可,是不是非常地优雅?

Functional Options 这种编程模式,我们经常能在各种项目中找到它的身影。例如,我在 tidb 项目中仅使用 opts ... 关键字搜索,就能看到这么多使用了 Functional Options 的代码(截图还未包括全部)。

Ein Programmiermodell, das in vielen Go-Projekten aktiv ist

Zusammenfassung

Das Funktionsoptionsmuster löst das Problem der dynamischen und flexiblen Konfiguration von Parametern für Objekte, muss jedoch in geeigneten Szenarien verwendet werden.

Wenn die Konfigurationsparameter des Objekts komplex sind, z. B. viele optionale Parameter, nicht importierte Felder, Parameter, die mit der Version zunehmen können usw., kann uns der Funktionsoptionsmodus sehr hilfreich sein.

Das obige ist der detaillierte Inhalt vonEin Programmiermodell, das in vielen Go-Projekten aktiv ist. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:Go语言进阶学习. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen