golang 泛型 middleware 設(shè)計(jì)模式: 一次只做一件事
1. 前言
本文主要介紹 在使用 gRPC 和 Gin 框架中常用的 middleware 設(shè)計(jì)模式
還有幾種叫法
- 裝飾器模式
- Pipeline 模式
設(shè)計(jì)思想:
- 10 個(gè) 10 行函數(shù), 而不是 1 個(gè) 100 行函數(shù)
- 一次只做一件事, 而不一次做多件事
- 單一職責(zé)
2. 代碼
已生產(chǎn)環(huán)境中大量使用, 每日?qǐng)?zhí)行千萬(wàn)次
package chain
type Ctx[T any] struct {
in T // 數(shù)據(jù)入?yún)? fns []func(c *Ctx[T], in T) (err error)
idx int
}
func NewCtx[T any](in T) *Ctx[T] {
return &Ctx[T]{
in: in,
idx: -1,
}
}
func (c *Ctx[T]) Next() (err error) {
c.idx++
for ; c.idx < len(c.fns); c.idx++ {
err = c.fns[c.idx](c, c.in)
if err != nil {
return
}
}
return
}
func (c *Ctx[T]) Add(fns ...func(c *Ctx[T], in T) (err error)) {
c.fns = append(c.fns, fns...)
}
3. test case
package chain
import (
"fmt"
"testing"
"time"
)
type Input struct {
a int
}
func TestNewCtx(t *testing.T) {
// 初始化
in := Input{a: 1}
c := NewCtx(&in)
// 添加中間件
c.Add(ctx1_cost) // 記錄耗時(shí)
c.Add(ctx2_add) // 數(shù)據(jù)加工
c.Add(ctx3_product) // 數(shù)據(jù)加工2
// 執(zhí)行
err := c.Next()
if err != nil {
panic(err)
}
// 檢查結(jié)果
fmt.Println(in.a)
if in.a != 4 {
panic(fmt.Sprintf("expect 4, but got %d", in.a))
}
}
func ctx1_cost(c *Ctx[*Input], in *Input) (err error) {
start := time.Now()
defer func() {
cost := time.Since(start)
fmt.Println("cost:", cost)
}()
err = c.Next()
return
}
func ctx2_add(c *Ctx[*Input], in *Input) (err error) {
in.a += 1
return
}
func ctx3_product(c *Ctx[*Input], in *Input) (err error) {
in.a *= 2
return
}