Go设计模式(二)Go世界里的黑话

在Go的世界里有一些特有的设计模式,这些设计模式利用了Go语言的特性,解决了特定的问题,这些设计模式很多Gopher都会如数家珍,我们称之为Go世界里的黑话。

中间件模式(Middleware)

中间件模式本质上是装饰模式(Decorator)在Go里的实现,他利用了Go函数式编程的思想。他可以动态添加一些横向的功能,类似于面向对象里的AOP

go 复制代码
type Handler func(w http.ResponseWriter, r *http.Request)

func LoggerMiddleware(handler Handler) Handler {
    return func(w http.ResponseWriter, r *http.Request) {
       log.Printf("[access] %s", r.URL.String())
       handler(w, r)
    }
}

func PingHandle(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("ping"))
}

func HelloHandle(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello"))
}

func main() {
    http.HandleFunc("/ping", LoggerMiddleware(PingHandle))
    http.HandleFunc("/hello", LoggerMiddleware(HelloHandle))

    http.ListenAndServe(":8080", nil)
}

多层中间件

middleware.go

go 复制代码
package middleware

import "net/http"

type MultiMiddleware struct {
    middleware []Middleware
}

type Handler func(w http.ResponseWriter, r *http.Request)

type Middleware func(Handler) Handler

func NewMultiMiddleware() *MultiMiddleware {
    return &MultiMiddleware{}
}

func (m *MultiMiddleware) Use(middleware Middleware) {
    m.middleware = append(m.middleware, middleware)
}

func (m *MultiMiddleware) Middleware(handler Handler) Handler {
    for _, middleware := range m.middleware {
       handler = middleware(handler)
    }
    return handler
}

main.go

go 复制代码
package main

import (
    "log"
    "net/http"
    "testy/middleware"
)

func LoggerMiddleware(handler middleware.Handler) middleware.Handler {
    return func(w http.ResponseWriter, r *http.Request) {
       log.Printf("[logger] %s", r.URL.String())
       handler(w, r)
    }
}

func RequestMiddleware(handler middleware.Handler) middleware.Handler {
    return func(w http.ResponseWriter, r *http.Request) {
       log.Printf("[request] %s", r.URL.String())
       handler(w, r)
    }
}

func PingHandle(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("ping"))
}

func HelloHandle(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello"))
}

func main() {

    m := middleware.NewMultiMiddleware()
    m.Use(LoggerMiddleware)
    m.Use(RequestMiddleware)

    http.HandleFunc("/ping", m.Middleware(PingHandle))
    http.HandleFunc("/hello", m.Middleware(HelloHandle))

    http.ListenAndServe(":8080", nil)
}

选项模式

选项模式属于创建型模式的一种,适用于复杂对象的初始化,当对象初始化时大部分成员变量都使用默认值,只想对某一些成员赋值时,就可以使用选项模式

go 复制代码
type Config struct {
    Timeout time.Duration
    Retry   bool
}

type Option func(config *Config)

func WithTimeout(timeout time.Duration) Option {
    return func(config *Config) {
       config.Timeout = timeout
    }
}

func WithRetry() Option {
    return func(config *Config) {
       config.Retry = true
    }
}

type Client struct {
    config *Config
}

func NewClient(opt ...Option) *Client {
    config := &Config{
       Timeout: time.Second,
       Retry:   false,
    }

    for _, option := range opt {
       option(config)
    }

    c := &Client{config: config}
    return c
}

func main() {
    c := NewClient(WithTimeout(time.Hour), WithRetry())
    fmt.Println(c.config)  // 结果 &{1h0m0s true}

}

函数转接口对象(Function to interface object)

实现函数向接口对象的转换,这样使用者用起来就会非常灵活,在net.http包也用了这个模式(HandlerFunc),下面这个例子是把Redis函数转换成CacheInterface接口的对象

go 复制代码
type CacheInterface interface {
    Check(a string) error
}

func NewCache(cache CacheInterface) {
    fmt.Println(cache.Check("abc"))
}

type RevertFunc func(a string) error

func (r RevertFunc) Check(a string) error {
    return r(a)
}

func Revert2Cache(a func(a string) error) CacheInterface {
    return RevertFunc(a)
}

func Redis(a string) error {
    return nil
}

func main() {
    NewCache(Revert2Cache(Redis))
}
相关推荐
踏着七彩祥云的小丑12 小时前
Go学习第9天:并发编程 + 文件操作 + 正则表达式
学习·golang·正则表达式·go
止语Lab16 小时前
Go 代码生成的三层认知:从忍住不用到自己造轮子
go
协享科技18 小时前
AI 视频理解:让 Agent 看视频并总结内容
人工智能·go·音视频·agent·ai编程
曲幽2 天前
掏出手机就能搭个 WebDAV 同步服务器?这操作有点香
go·termux·tampermonkey·sync·webdav·filebrowser·gowebdav·koreader
Code_Artist2 天前
🦜用 GoAI 从零打造一个 AI Agent 脚手架工程:重新定义智能体开发范式!
go·agent·ai编程
ShuiShenHuoLe3 天前
OS的常用函数
go
踏着七彩祥云的小丑3 天前
Go学习第8天:接口 + 泛型 + 错误处理
开发语言·学习·golang·go
蓝宝石的傻话4 天前
rpi-cam:给 Raspberry Pi 造的轻量级 ONVIF 相机服务
go·iot·nvr
蓝宝石的傻话4 天前
VictoriaMetrics指标流聚合三年回顾与现状(2026)
go·prometheus·victoriametrics
踏着七彩祥云的小丑4 天前
Go学习第7天:Map集合 + 递归函数 + 类型转换
开发语言·学习·golang·go