前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Go设计模式实战--用职责链实现购物车与商品优惠的解耦

Go设计模式实战--用职责链实现购物车与商品优惠的解耦

作者头像
KevinYan
发布2025-03-13 21:16:20
发布2025-03-13 21:16:20
4300
代码可运行
举报
文章被收录于专栏:网管叨bi叨网管叨bi叨
运行总次数:0
代码可运行

上一节「Go项目实战-购物车功能的核心接口开发」中我们完成了购物车模块的基本功能的开发,所有购物车功能中存在变数的就是购物车的账单结算功能,也是未来经常可能会遇到需求改动的功能?各种促销活动相关的需求都会要求涵盖在这个功能中。

我们理解的购物车结算功能,一开始可能是是下面这个清纯版的

但实际上公司产品要求的购物车结算功能是下面这张图这样,不光能算出商品总价,还要能综合考虑用户是不是VIP,有没有优惠券、够不够参加满减活动。

而且促销活动的玩法可能远不止这么多未来还有可能增加新的玩法。每次新增一个玩法我们的结算模块代码大概率又需要增加一个代码分支,做相应的查询和判断等等操作来满足新的促销玩法。

那么有没有什么设计模式能让我们稍微缓解一下代码不停添加条件分支来适应新需求呢?我这么说了,当然是有了,这就是职责链模式,也有的资料叫责任链模式。本节我们把购物车的账单结算功能使用职责链进行改造,让它支持优惠券、满减活动、VIP折扣能促销功能的应用。

不过首先我们需要聊一下什么是责任链模式。

本节节选自我的专栏《Go项目搭建和整洁开发实战》欢迎扫码订阅

我们在付费项目的实战中还专门提供了一个职责链在业务代码中应用的模版,大家应用时替换到实际代码即可使用,订阅后还可加入专属读者群一起学习。

职责链模式

职责链在很多流行框架里都有被用到,像中间件、拦截器等框架组件都是应用的这种设计模式,这两个组价大家应该用的比较多。但其实在一些核心的业务中,应用职责链模式也能够让我们“相对无痛地”扩展业务流程的步骤。

注意我上面的用词“相对无痛”,意思是我们不用不停地在原有步骤中增加if else 判断,不必修改原有已经开发好,经过测试的流程。但还是有些代码开发成本的,也会增加代码的复杂度,真正做到“无痛”,那你的转个行当甲方,最好是当老板才行。。。

职责链的实现步骤分析

我们通过上面流程扩展的痛点可以想到,流程中每个步骤都应由一个处理对象来完成逻辑抽象、所有处理对象都应该提供统一的处理自身逻辑的方法,其次还应该维护指向下一个处理对象的引用,当前步骤自己逻辑处理完后,就调用下一个对象的处理方法,把请求交给后面的对象进行处理,依次递进直到流程结束。

如果抽象成 UML 类图表示的话,差不多就是下面这个样子。

了解完职责链模式从接口和类型设计上应该怎么实现后,我们进入代码实现环节。

用职责链模式改造购物车结算功能

以我们项目的购物车结算功能在加入促销相关的需求后,其流程如下:

查购物信息--> 查看的可用优惠券--> 查满减活动-->查VIP资格和折扣-->生成账单信息。

开头和结尾的步骤固定,不管什么类型的用户都会有这个流程,中间的促销流程则是变数,我们的目标是利用职责链模式,实现这个流程中的每个步骤,且相互间不耦合,还支持向流程中增加步骤。

改造结算功能的第一步,是先确定新的结算功能返回的响应,我们把购物车功能结算的响应对象改造为以下结构,增加了促销相关的信息,这样客户端拿到后也能展示给用户,让用户知道自己用了哪些优惠。

新的购物车结算功能的响应对象如下。

代码语言:javascript
代码运行次数:0
运行
复制
type CheckedCartItemBillV2 struct {
 Items      []*CartItem `json:"items"`
 BillDetail struct {
  Coupon struct { // 可用的优惠券
   CouponId      int64`json:"coupon_id"`
   CouponName    string`json:"coupon_name"`
   DiscountMoney int    `json:"discount_money"`
  } `json:"coupon"`
  Discount struct { // 可用的满减活动券
   DiscountId    int64`json:"discount_id"`
   DiscountName  string`json:"discount_name"`
   DiscountMoney int    `json:"discount_money"`
  } `json:"discount"`
  VipDiscountMoney   int`json:"vip_discount_money"`   // VIP减免的金额
  OriginalTotalPrice int`json:"original_total_price"`// 减免、优惠前的总金额
  TotalPrice         int`json:"total_price"`          // 实际要支付的总金额
 } `json:"bill_detail"`
}

我们服务层使用的领域对象也需要做调整。

代码语言:javascript
代码运行次数:0
运行
复制
type CartBillInfo struct {
 Coupon struct { // 可用的优惠券
  CouponId      int64
  CouponName    string
  DiscountMoney int
  Threshold     int// 使用门槛, 比如满1000 可用

 }
 Discount struct { // 可用的满减活动券
  DiscountId    int64
  DiscountName  string
  DiscountMoney int
  Threshold     int// 使用门槛, 比如满1000 可用
 }
 VipDiscountMoney   int// VIP减免的金额
 OriginalTotalPrice int// 减免、优惠前的总金额
 TotalPrice         int// 实际要支付的总金额
}

接下来我们先来实现职责链模式里的公共部分—即模式的接口和抽象类,在logic/domainservice中新建cart_bill_checker.go 新增以下Interface。

代码语言:javascript
代码运行次数:0
运行
复制
type cartBillCheckHandler interface {
 RunChecker(*CartBillChecker) error
 SetNext(cartBillCheckHandler) cartBillCheckHandler
 Check(*CartBillChecker) error
}

接下来定义 cartCommonChecker ,它充当抽象类型,实现公共方法。

代码语言:javascript
代码运行次数:0
运行
复制

type cartCommonChecker struct {
 nextHandler cartBillCheckHandler
}

func (n *cartCommonChecker) SetNext(handler cartBillCheckHandler) cartBillCheckHandler {
 n.nextHandler = handler
return handler
}

func (n *cartCommonChecker) RunChecker(billChecker *CartBillChecker) (err error) {
if n.nextHandler != nil {
if err = n.nextHandler.Check(billChecker); err != nil {
   err = errcode.Wrap("CartBillCheckerError", err)
   return
  }

return n.nextHandler.RunChecker(billChecker)
 }

return
}

抽象方法 Check 则留给像下面优惠券处理类 couponChecker 这样的匿名嵌套了 cartCommonChecker 的具体处理类去实现。

我们来实现couponChecker、discountChecker、vipChecker 三个具体的流程步骤的处理类,他们各自要处理的逻辑都封装在自己实现的Check方法中。

在项目中我们提供了一个职责链在业务代码中应用的模版,大家应用时替换到实际代码即可使用。

加入专栏后除了能获得完整版教程,更有配套的实战项目和专属读者群,我在其中用git tag版本编排好了每节教程对应的代码更新,让你能更容易地追踪项目开发过程中的每一处代码变更。

《Go项目搭建和整洁开发实战》专栏分为五大部分,重点章节如下

  • 第一部分介绍让框架变得好用的诸多实战技巧,比如通过自定义日志门面让项目日志更简单易用、支持自动记录请求的追踪信息和程序位置信息、通过自定义Error在实现Go error接口的同时支持给给错误添加错误链,方便追溯错误源头。
  • 第二部分:讲解项目分层架构的设计和划分业务模块的方法和标准,让你以后无论遇到什么项目都能按这套标准自己划分出模块和逻辑分层。后面几个部分均是该部分所讲内容的实践。
  • 第三部分:设计实现一个套支持多平台登录,Token泄露检测、同平台多设备登录互踢功能的用户认证体系,这套用户认证体系既可以在你未来开发产品时直接应用
  • 第四部分:商城app C端接口功能的实现,强化分层架构实现的讲解,这里还会讲解用责任链、策略和模版等设计模式去解决订单结算促销、支付方式支付场景等多种多样的实际问题。
  • 第五部分:单元测试、项目Docker镜像、K8s部署和服务保障相关的一些基础内容和注意事项。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-03-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 网管叨bi叨 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 职责链模式
  • 职责链的实现步骤分析
  • 用职责链模式改造购物车结算功能
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档