一、背景
在日常编码中,通过设计模式来减少代码复杂性是不可或缺的一部分,针对与一次请求需要完成多个业务逻辑来说 分层 则是必不可少的代码抽象实现方案。
通常在分层前,需要合理的抽象当前业务系统的主要流程
比如在营销域的一种常见的任务玩法:用户购买10次商品(电商下单)可以获得1个实物奖品or抽奖机会or xx,则可以拆分成:
- 用户上报数据处理层
- 依赖数据加载层
- 任务达成判定层
- 奖品发放层
- 实时透出展示层
二、编码设计
通常分层也伴随着全局上下文(模块化能力),业务上报的参数、依赖的数据、以及各个模块自定义的业务逻辑会放到全局上下文内处理。
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)
}
}