golang 责任链模式(链式调用)

golang 链式调用



前言

我们在写golang 代码的时候经常会出现我想有一个可变参数来确认初始化变量的问题或者针对于按照多种条件查询返回查询结果。

我个人比较推崇使用责任链模式(链式调用)的方式来处理,这样的代码维护简单容易理解。


一、什么是「责任链模式」?

首先把一系列业务按职责划分成不同的对象,接着把这一系列对象构成一个链,然后在这一系列对象中传递请求对象,直到被处理为止。

我们从概念中可以看出责任链模式有如下明显的优势:

按职责划分:解耦
对象链:逻辑清晰

但是有一点直到被处理为止,代表最终只会被一个实际的业务对象执行了实际的业务逻辑,明显适用的场景并不多。但是除此之外,上面的那两点优势还是让人很心动,所以,为了适用于目前所接触的绝大多数业务场景,把概念进行了简单的调整,如下:

首先把一系列业务按职责划分成不同的对象,接着把这一系列对象构成一个链,直到“链路结束”为止。(结束:异常结束,或链路执行完毕结束)

简单的直到“链路结束”为止转换可以让我们把责任链模式适用于任何复杂的业务场景。

二、「责任链模式」的具体优势

直观:一眼可观的业务调用过程
无限扩展:可无限扩展的业务逻辑
高度封装:复杂业务代码依然高度封装
极易被修改:复杂业务代码下修改代码只需要专注对应的业务类(结构体)文件即可,以及极易被调整的业务执行顺序

三、代码案例

以按照多种条件查询返回查询结果为例

search.go

package order

import (
	"time"
)

type Option func(*Options)

// Options  每次请求的上下文数据
type Options struct {
	OrderId    uint64
	UserId     uint64
	GoodsId    uint64
	ProductId  uint64
	MerchantId uint64
	PkgId      uint64

	Status         uint8
	DeliveryStatus uint8

	HasInvoice  string
	UserNick    string
	ProductName string
	MobilePhone string

	OrderByType string
	StartTime   time.Time
	EndTime     time.Time
	PageNum     int
	PageSize    int
}

// FilterByOrderId 按照 order_id 过滤
func FilterByOrderId(orderId uint64) Option {
	return func(o *Options) {
		o.OrderId = orderId
	}
}

// FilterByUserId 按照 user_id 过滤
func FilterByUserId(userId uint64) Option {
	return func(o *Options) {
		o.UserId = userId
	}
}

// FilterByGoodsId 按照 goods_id 过滤
func FilterByGoodsId(goodsId uint64) Option {
	return func(o *Options) {
		o.GoodsId = goodsId
	}
}

// FilterByProductId 按照 product_id 过滤
func FilterByProductId(productId uint64) Option {
	return func(o *Options) {
		o.ProductId = productId
	}
}

// FilterByMerchantId 按照 merchant_id 过滤
func FilterByMerchantId(merchantId uint64) Option {
	return func(o *Options) {
		o.MerchantId = merchantId
	}
}

// FilterByPkgId 按照 merchant_id 过滤
func FilterByPkgId(pkgId uint64) Option {
	return func(o *Options) {
		o.PkgId = pkgId
	}
}

// FilterByStatus 按照 status 过滤
func FilterByStatus(status uint8) Option {
	return func(o *Options) {
		o.Status = status
	}
}

// FilterByDeliveryStatus 按照 delivery_status 过滤
func FilterByDeliveryStatus(deliveryStatus uint8) Option {
	return func(o *Options) {
		o.DeliveryStatus = deliveryStatus
	}
}

// FilterByHasInvoice 按照 has_invoice 过滤
func FilterByHasInvoice(hasInvoice string) Option {
	return func(o *Options) {
		o.HasInvoice = hasInvoice
	}
}

// FilterByUserNick 按照 user_nick 过滤
func FilterByUserNick(userNick string) Option {
	return func(o *Options) {
		o.UserNick = userNick
	}
}

// FilterByProductName 按照 ProductName 过滤
func FilterByProductName(productName string) Option {
	return func(o *Options) {
		o.ProductName = productName
	}
}

// FilterByCreateAt 按照 create_at 过滤
func FilterByCreateAt(startTime, endTime time.Time) Option {
	return func(o *Options) {
		o.StartTime = startTime
		o.EndTime = endTime
	}
}

// OrderByCreateAt 按照create_at过滤
func OrderByCreateAt(orderByType string) Option {
	return func(o *Options) {
		o.OrderByType = orderByType
	}
}

// RecordsByPage 按照分页输出
func RecordsByPage(page, pageSize int) Option {
	return func(o *Options) {
		o.PageNum = page
		o.PageSize = pageSize
	}
}

orders.go

package order

import (
	"context"
	"fmt"

	common "backend/storage/gorm"
	"backend/storage/gorm/model"

	"gorm.io/gorm"
)

var _ OrdersClient = (*ordersClient)(nil)

// OrdersClient 订单客户端
type OrdersClient interface {
	GetDB() *gorm.DB
	UpdateOrdersByOrderID(ctx context.Context, updateInfo *model.Orders) error
	GetSearchInfo(ctx context.Context, opts ...Option) ([]*model.Orders, error)
	CountByToSend(ctx context.Context, countInfo *model.StatusCount) (int, error)
}

// ordersClient 订单结构体
type ordersClient struct {
	db *gorm.DB
}

// GetDB 获取DB
func (a *ordersClient) GetDB() *gorm.DB {
	return a.db
}

// UpdateOrdersByOrderID 按照 OrderID 过滤然后非零更新
func (o *ordersClient) UpdateOrdersByOrderID(ctx context.Context, updateInfo *model.Orders) error {
	return o.db.
		Where("order_id = ? ", updateInfo.OrderId).
		Updates(updateInfo).
		WithContext(ctx).
		Error
}

// CountByToSend 按照未发货记录数据
func (o *ordersClient) CountByToSend(ctx context.Context, countInfo *model.StatusCount) (int, error) {
	statusCount := model.StatusCount{}
	err := o.db.
		Select("status, count(*) as count").
		Where("status = ? ", countInfo.Status).
		Scan(&statusCount).
		Error
	if err != nil {
		return 0, err
	}
	return countInfo.Count, nil
}

// GetSearchInfo 通过多项参数信息 进行数据检索
func (a *ordersClient) GetSearchInfo(ctx context.Context, opts ...Option) ([]*model.Orders, error) {
	var options Options
	db := a.db
	orders := make([]*model.Orders, 0)

	for _, opt := range opts {
		opt(&options)
	}

	if options.OrderId != 0 {
		db = db.Where("order_id = ? ", options.OrderId)
	}

	if options.UserNick != "" {
		db = db.Where("user_nick like %?% ", options.UserNick)
	}

	if options.StartTime.IsZero() && options.EndTime.IsZero() {
		db = db.Where("create_at >= ? and create_at < ? ", options.StartTime, options.EndTime)
	}

	if options.Status != 0 {
		db = db.Where("status = ? ", options.Status)
	}

	if options.DeliveryStatus != 0 {
		db = db.Where("refund_status = ? ", options.DeliveryStatus)
	}

	if options.UserId != 0 {
		db = db.Where("user_id = ? ", options.UserId)
	}

	if options.OrderByType == common.DescendSort {
		db = db.Order(fmt.Sprintf("create_at %s", options.OrderByType))
	}

	if options.PageNum > 0 && options.PageSize > 0 {
		db = db.Limit(options.PageSize).Offset((options.PageNum - 1) * options.PageSize)
	}

	err := db.Unscoped().Find(&orders).Error
	if err != nil {
		return nil, err
	}

	return orders, nil
}


总结

代码案例为个人编写,个人代码风格不喜勿喷, 有任何问题请与我联系。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值