Go 設計模式:責任鏈和函數選項,讓你的代碼更優雅!

最近接觸到越來越多有歷史 “沉澱” 的 Go 項目,深感設計模式和及時干預的重要性。近期會分享一些設計模式,一起學習代碼設計!

今天的分享的設計模式是:責任鏈和函數選項模式。在日常程序裏是比較常用的。很多開源庫中也有使用。

責任鏈模式

責任鏈模式(Chain of Responsibility Pattern)是一種行爲設計模式,它允許對象將請求沿處理程序鏈進行傳遞。

程序鏈既可以處理請求,也可以繼續將請求傳遞給鏈中的下一個處理程序。請求沿着處理程序鏈傳遞,直到請求被處理或到達處理程序鏈的末端。

這類場景的例子包括:事件處理、日誌記錄和錯誤處理等類似攔截器注入的用法。

例子

我們將會創建一個簡單例子來演示 Go 中的責任鏈模式。

在這個例子中,責任鏈將負責驗證請求、打印錯誤日誌和處理請求本身。

具體代碼如下:

package service

import "fmt"

type Service interface {
    HelloWorld(name string) (string, error)
}

type service struct {}

func (s service) HelloWorld(name string) (string, error) {
    return fmt.Sprintf("Hello World from %s", name), nil
}

type validator struct {
    next Service
}

func (v validator) HelloWorld(name string) (string, error) {
    if len(name) <= 3 {
        return "", fmt.Errorf("name length must be greater than 3")
    }

    return v.next.HelloWorld(name)
}

type logger struct {
    next Service
}

func (l logger) HelloWorld(name string) (string, error) {
    res, err := l.next(name)

    if err != nil {
        fmt.Println("error:", err)
        return res, err
    }

    fmt.Println("HelloWorld method executed successfuly")
    return res, err
}

func New() Service {
    return logger{
        next: validator {
            next: service{},
        },
    }
}

入口 main 函數使用:

package main

import (
    "fmt"
    "service"
)

func main() {
    s := service.New()

    res, err := s.HelloWorld("煎魚")
    fmt.Println(res, err) // Hello World from 煎魚

    res, err := s.HelloWorld("edd")
    fmt.Println(res, err) // name length must be greater than 3
}

在本例中,我們創建了一個實現 Service 接口的簡單服務。Service 接口定義了一個方法 HelloWorld,該方法將名稱作爲參數,並返回一條 Hello World 信息。

我們還創建了兩個額外的結構體 validator 和 logger,它們都實現了 Service 接口。

validator 結構會驗證名稱的長度,如果長度小於或等於 3,則返回錯誤信息。當 HelloWorld 方法成功執行時,logger 結構會打印錯誤日誌和成功信息。

New 函數通過將 validator 和 logger 結構與 Service 結構鏈起來,創建了一個處理程序鏈。

Service 結構體的方法是鏈中的最後一個處理程序,如果請求通過驗證,它將處理請求。

例子中 next 字段的作用是什麼

next 字段用於保存鏈中的下一個處理程序。

當在一個處理程序上調用 HelloWorld 方法時,會使用 next 字段在鏈中的下一個處理程序上調用 HelloWorld 方法。

對照看可以得知,validator 和 logger 結構體中的 next 字段,是用於鏈式處理程序的關鍵字段。

函數選項模式

函數選項模式(Function Options Pattern)是一種很常見的設計模式,它允許開發人員通過使用 Options 作爲參數,爲函數或方法提供靈活且可定製的行爲。

常用於 Go 庫和框架,爲用戶提供簡潔明瞭的 API。經常在我們使用的基礎庫能看到,例如:grpc-go。

例子

我們有一個用 Go 表示 HTTP 服務器的 Server 結構體作爲基礎。

我們希望爲用戶提供配置 HTTP Server 各方面的功能,例如:監聽的端口、超時時間以及是否啓用日誌記錄等。

具體代碼如下:

package main

import "fmt"

type Server struct {
    Host     string
    Port     int
    Protocol string
    Timeout  int
}

type ServerOption func(*Server)

func WithHost(host string) ServerOption {
    return func(s *Server) {
        s.Host = host
    }
}

func WithPort(port int) ServerOption {
    return func(s *Server) {
        s.Port = port
    }
}

func WithProtocol(protocol string) ServerOption {
    return func(s *Server) {
        s.Protocol = protocol
    }
}

func WithTimeout(timeout int) ServerOption {
    return func(s *Server) {
        s.Timeout = timeout
    }
}

func NewServer(options ...ServerOption) *Server {
    server := &Server{
        Host:     "localhost",
        Port:     8080,
        Protocol: "http",
        Timeout:  30,
    }

    for _, option := range options {
        option(server)
    }

    return server
}

func main() {
    server := NewServer(
        WithHost("eddycjy.com"),
        WithPort(9000),
        WithProtocol("https"),
        WithTimeout(60),
    )

    fmt.Printf("Server: %+v\n", server)
}

解決了什麼問題

總結

一個好的設計模式,可以讓你的項目更具有易讀性。程序編寫和使用起來更加的舒心。今天給大家介紹的責任鏈模式和函數可選模式,是非常常用的。

推薦大家可以嘗試應用到自己的 Go 項目中去,想必會有非常大的幫助!

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/ow1un48RY7qInx4YCQzV1g