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

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


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

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

图片图片

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

图片图片

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

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

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

职责链模式

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

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

职责链的实现步骤分析

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

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

图片图片

图片图片

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

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

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

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

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

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

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

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"`
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

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

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// 实际要支付的总金额
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

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

type cartBillCheckHandler interface {
 RunChecker(*CartBillChecker) error
 SetNext(cartBillCheckHandler) cartBillCheckHandler
 Check(*CartBillChecker) error
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

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

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
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

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

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

责任编辑:武晓燕 来源: 网管叨bi叨
相关推荐

2024-12-02 08:30:19

2025-03-10 09:07:20

2022-12-16 08:52:14

购物车系统存储

2009-07-07 15:57:29

JSP购物车

2015-08-03 11:48:12

购物车动画

2022-06-28 14:42:26

ETS购物车应用

2011-04-14 10:08:04

AJAXPHPJQuery

2024-12-05 09:13:55

Go项目模块

2023-01-09 08:43:53

Go设计模式

2021-02-01 09:57:29

鸿蒙HarmonyOS应用

2023-03-03 08:12:07

设计模式语言

2018-05-28 09:53:12

京东购物车Java

2022-09-02 08:23:12

软件开发解耦架构

2020-10-16 18:41:43

command设计模式代码

2021-01-07 10:30:23

设计模式

2023-11-08 08:01:40

Spring购物车代码

2012-10-08 11:18:05

JavaMVC项目

2022-09-13 16:01:13

购物车京东接口

2009-07-28 13:47:47

ASP.NET电子商务ASP.NET购物车

2025-02-11 07:55:45

点赞
收藏

51CTO技术栈公众号