一种常用业务分层理念【Go】实现

122 阅读2分钟

一、背景

在日常编码中,通过设计模式来减少代码复杂性是不可或缺的一部分,针对与一次请求需要完成多个业务逻辑来说 分层 则是必不可少的代码抽象实现方案。

通常在分层前,需要合理的抽象当前业务系统的主要流程

比如在营销域的一种常见的任务玩法:用户购买10次商品(电商下单)可以获得1个实物奖品or抽奖机会or xx,则可以拆分成:

  1. 用户上报数据处理层
  2. 依赖数据加载层
  3. 任务达成判定层
  4. 奖品发放层
  5. 实时透出展示层

二、编码设计

通常分层也伴随着全局上下文(模块化能力),业务上报的参数、依赖的数据、以及各个模块自定义的业务逻辑会放到全局上下文内处理。

2.1 全局上下文

type xxCtx struct {
    Ctx context.Context                   // 上下文数据
    RequestParams map[string]interface{}  // 请求参数
    ResourceData  map[string]interface{}  // 数据源
    ShowData      map[strint]interface{}  // 展示数据
}

这里定义的每一个struct会在个字领域内进行填充处理。

这里针对于Ctx可以通过go sync.Pool来优化处理性能

2.2 设计模式

首先,需要定义每一层的动作,大概分为成功执行和失败执行。每一层都需要继承这个interface{}

type LayerHandle interface {
    Output() error
    ErrResponse()
}

type Handle struct {
    args any
}

func NewLogicHandle(args any) *Handle {
    return &Handle{args: args}
}

func (h *Handle) Dispatch(handle ...LayerHandle) error {
    for _, h := range handle {
       if err := h.Output(); err != nil {
          h.ErrResponse()
          return err
       }
    }
    return nil
}

一下为test

// 控制执行的层级顺序以及数量,当然这里也可以并行执行,如果每一个层级不耦合
var Process = func() []LayerHandle {
    return []LayerHandle{
       &LoadLayer{},
    }
}

// LoadLayer 定义一个业务加载层
type LoadLayer struct {
}

// 成功执行输出
func (*LoadLayer) Output() error {
    fmt.Println("output")
    return nil
}

// 失败执行输出
func (*LoadLayer) ErrResponse() {
    return
}

func TestHandle_Dispatch(t *testing.T) {
    l := NewLogicHandle(1)
    if err := l.Dispatch(Process()...); err != nil {
       t.Log(err)
    }
}