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 信息。

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

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

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

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

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

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

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

對照看可以得知,validatorlogger 結構體中的 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