自学内容网 自学内容网

golang 泛型 middleware 设计模式: 一次只做一件事

golang 泛型 middleware 设计模式: 一次只做一件事

1. 前言

本文主要介绍 在使用 gRPC 和 Gin 框架中常用的 middleware 设计模式

还有几种叫法

  1. 装饰器模式
  2. Pipeline 模式

设计思想:

  1. 10 个 10 行函数, 而不是 1 个 100 行函数
  2. 一次只做一件事, 而不一次做多件事
  3. 单一职责

2. 代码

已生产环境中大量使用, 每日执行千万次

package chain

type Ctx[T any] struct {
in  T // 数据入参
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)    // 记录耗时
c.Add(ctx2_add)     // 数据加工
c.Add(ctx3_product) // 数据加工2

// 执行
err := c.Next()
if err != nil {
panic(err)
}

// 检查结果
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
}


原文地址:https://blog.csdn.net/jarvan5/article/details/143665690

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!