切換語言為:簡體

圖解Go中的Option模式:靈活配置與可選過濾

  • 爱糖宝
  • 2024-08-26
  • 2053
  • 0
  • 0

在 Go 語言開發中,設計靈活、可擴充套件的 API 是一項重要技能。而 Option 模式是一種常見且有效的方法,它允許我們為函式提供可選引數,並使程式碼更加簡潔和可讀。

在這篇文章中,我將透過兩種常見的應用方式,展示如何使用 Option 模式建立可選配置和可選過濾的功能。

1. 可選配置(Optional Configuration)

可選配置是一種常見的使用場景,例如建立一個物件時,某些欄位是可選的,使用者可以選擇性地設定這些欄位。

程式碼示例:

package main

import "fmt"

type User struct {
    Name string
    Age  int
}

// Option 型別,定義一個函式型別
type userOption func(u *User)

// WithAge 返回一個設定 Age 的 Option
func WithAge(age int) userOption {
    return func(u *User) {
        u.Age = age
    }
}

// WithName 返回一個設定 Name 的 Option
func WithName(name string) userOption {
    return func(u *User) {
        u.Name = name
    }
}

// NewUser 使用可選的 Option 建立一個 User
func NewUser(options ...userOption) *User {
    u := new(User)
    for _, option := range options {
        option(u)
    }
    return u
}

在這個例子中,userOption 是一個函式型別,可以對 User 結構體進行操作。透過 WithAgeWithName 函式,我們可以生成相應的 userOption,然後在建立 User 物件時使用這些可選配置項。

使用示例:

func main() {
    u1 := NewUser(WithName("xx"), WithAge(11))
    fmt.Printf("%+v\n", u1) // 輸出:{Name:xx Age:11}
}

在這個示例中,我們只需提供我們關心的配置項即可,未提供的配置項將保持預設值。這種方法使得 API 更加靈活,使用者可以選擇性地傳遞引數,而不需要定義一大堆建構函式。

圖解Go中的Option模式:靈活配置與可選過濾

  • main 函式:


    • u1 是一個指標,指向 User 結構體在記憶體中的位置。

  • NewUser 函式:


    • User 結構體分配在記憶體中,假設地址為 0x0010

    • User 結構體中包含 NameAge 欄位,Name 欄位指向儲存 "xx" 的記憶體地址。

  • WithName 和 WithAge 函式:


    • WithName 函式將 name 引數的值("xx")賦值給 User 結構體的 Name 欄位。

    • WithAge 函式將 age 引數的值(11)賦值給 User 結構體的 Age 欄位。

2. 可選過濾(Optional Filtering)

Option 模式的另一個強大應用是在數據處理時進行可選過濾。例如,當我們有一組資料需要根據不同的條件進行過濾時,可以透過 Option 模式實現靈活的過濾條件組合。

程式碼示例:

package main

type QueryOption interface {
    Apply(u []*User) []*User
}

type Where struct {
    Name string
    Age  int
}

func (w *Where) Apply(u []*User) []*User {
    res := make([]*User, 0, len(u))
    for _, v := range u {
        if v.Age == w.Age && v.Name == w.Name {
            res = append(res, v)
        }
    }
    return res
}

type Limit struct {
    Offset int
    Limit  int
}

func (l *Limit) Apply(u []*User) []*User {
    right := l.Limit + l.Offset
    if right >= len(u) {
        return u
    }
    return u[l.Offset:right]
}

func Filter(u []*User, ops ...QueryOption) []*User {
    for _, op := range ops {
        u = op.Apply(u)
    }
    return u
}

在這個例子中,我們定義了 QueryOption 介面,並透過 WhereLimit 兩個結構體實現了可選過濾功能。每個過濾條件都實現了 Apply 方法,用來對 User 列表進行操作。

使用示例:

func main() {
    u1 := NewUser(WithName("xx"), WithAge(11))
    u2 := NewUser(WithName("yy"), WithAge(22))
    u3 := NewUser(WithName("xx"), WithAge(11))
    users := []*User{u1, u2, u3}

    // 過濾符合條件的資料
    result := Filter(users, &Where{Name: "xx", Age: 11}, &Limit{Offset: 0, Limit: 2})

    for _, v := range result {
        fmt.Printf("%+v\n", v)
    }
}

這裏我們使用了兩個過濾條件:WhereLimit,首先透過 Where 過濾出符合條件的使用者,然後透過 Limit 對結果集進行分頁。

圖解Go中的Option模式:靈活配置與可選過濾

Main函式:

  • u1, u2, u3User 結構體例項的指標。

  • users 是一個包含 u1u2u3 指標的切片。

  • result 是經過過濾後的結果切片,包含 u1u3

Filter函式:

  • 展示了 Filter 函式如何應用 WhereLimit 策略來生成最終結果。

總結:

Option 模式是一種極其靈活的設計模式,在 Go 中有著廣泛的應用。它透過將配置項和過濾條件封裝成函式或介面,使得程式碼更加簡潔、靈活,並且易於擴充套件。無論是在建立物件時的可選配置,還是在數據處理時的可選過濾,Option 模式都能幫助我們構建更加靈活的 API。

透過 Option 模式,我們可以避免定義大量的建構函式或方法過載,並且可以輕鬆地新增新的配置項或過濾條件而不破壞現有程式碼。這種設計模式對於構建可維護的、可擴充套件的程式碼庫非常有用。

以下為程式碼整體架構圖:

圖解Go中的Option模式:靈活配置與可選過濾

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.