订阅通知 | Go设计模式实战
嗯,Go设计模式实战系列,一个设计模式业务真实使用的golang系列。
前言
本系列主要分享,如何在我们的真实业务场景中使用设计模式。
本系列文章主要采用如下结构:
- 什么是「XX设计模式」?
- 什么真实业务场景可以使用「XX设计模式」?
- 怎么用「XX设计模式」?
虽然本文的题目叫做“订阅通知”,但是呢,本文却主要介绍「观察者模式」如何在真实业务场景中使用。是不是有些不理解?解释下:
- 原因一,「观察者模式」其实看起来像“订阅通知”
- 原因二,“订阅通知”更容易被理解
什么是「观察者模式」?
观察者观察被观察者,被观察者通知观察者
我们用“订阅通知”翻译下「观察者模式」的概念,结果:
“订阅者订阅主题,主题通知订阅者”
是不是容易理解多了,我们再来拆解下这句话,得到:
- 两个对象
- 被观察者 -> 主题
- 观察者 -> 订阅者
- 两个动作
- 订阅 -> 订阅者订阅主题
- 通知 -> 主题发生变动通知订阅者
观察者模式的优势:
- 高内聚 -> 不同业务代码变动互不影响
- 可复用 -> 新的业务(就是新的订阅者)订阅不同接口(主题,就是这里的接口)
- 极易扩展 -> 新增接口(就是新增主题);新增业务(就是新增订阅者);
其实说白了,就是分布式架构中使用消息机制MQ解耦业务的优势,是不是这么一想很容易理解了。
什么真实业务场景可以用「观察者模式」?
所有发生变更,需要通知的业务场景
详细说:只要发生了某些变化,需要通知依赖了这些变化的具体事物的业务场景。
我们有哪些真实业务场景可以用「观察者模式」呢?
比如,订单逆向流,也就是订单成立之后的各种取消操作(本文不讨论售后),主要有如下取消类型:
订单取消类型 |
---|
未支付取消订单 |
超时关单 |
已支付取消订单 |
取消发货单 |
拒收 |
在触发这些取消操作都要进行各种各样的子操作,显而易见不同的取消操作所涉及的子操作是存在交集的。其次,已支付取消订单的子操作应该是所有订单取消类型最全的,其他类型的复用代码即可,除了分装成函数片段,还有什么更好的封装方式吗?答案:「观察者模式」。
接着我们来分析下订单逆向流业务中的变与不变:
- 变
- 新增取消类型
- 新增子操作
- 修改某个子操作的逻辑
- 取消类型和子操作的对应关系
- 不变
- 已存在的取消类型
- 已存在的子操作(在外界看来)
怎么用「观察者模式」?
关于怎么用,完全可以生搬硬套我总结的使用设计模式的四个步骤:
- 业务梳理
- 业务流程图
- 代码建模
- 代码demo
业务梳理
注:本文于单体架构背景探讨业务的实现过程,简单容易理解。 |
第一步,梳理出所有存在的的逆向业务的子操作,如下:
所有子操作 |
---|
修改订单状态 |
记录订单状态变更日志 |
退优惠券 |
还优惠活动资格 |
还库存 |
还礼品卡 |
退钱包余额 |
修改发货单状态 |
记录发货单状态变更日志 |
生成退款单 |
生成发票-红票 |
发邮件 |
发短信 |
发微信消息 |
第二步,找到不同订单取消类型和这些子操作的关系,如下:
订单取消类型(“主题”)(被观察者) | 子操作(“订阅者”)(观察者) |
---|---|
取消未支付订单 | - |
- | 修改订单状态 |
- | 记录订单状态变更日志 |
- | 退优惠券 |
- | 还优惠活动资格 |
- | 还库存 |
超时关单 | - |
- | 修改订单状态 |
- | 记录订单状态变更日志 |
- | 退优惠券 |
- | 还优惠活动资格 |
- | 还库存 |
- | 发邮件 |
- | 发短信 |
- | 发微信消息 |
已支付取消订单(未生成发货单) | - |
- | 修改订单状态 |
- | 记录订单状态变更日志 |
- | 还优惠活动资格(看情况) |
- | 还库存 |
- | 还礼品卡 |
- | 退钱包余额 |
- | 生成退款单 |
- | 生成发票-红票 |
- | 发邮件 |
- | 发短信 |
- | 发微信消息 |
取消发货单(未发货) | - |
- | 修改订单状态 |
- | 记录订单状态变更日志 |
- | 修改发货单状态 |
- | 记录发货单状态变更日志 |
- | 还库存 |
- | 还礼品卡 |
- | 退钱包余额 |
- | 生成退款单 |
- | 生成发票-红票 |
- | 发邮件 |
- | 发短信 |
- | 发微信消息 |
拒收 | - |
- | 修改订单状态 |
- | 记录订单状态变更日志 |
- | 修改发货单状态 |
- | 记录发货单状态变更日志 |
- | 还库存 |
- | 还礼品卡 |
- | 退钱包余额 |
- | 生成退款单 |
- | 生成发票-红票 |
- | 发邮件 |
- | 发短信 |
- | 发微信消息 |
注:流程不一定完全准确、全面。
结论:
- 不同的订单取消类型的子操作存在交集,子操作可被复用。
- 子操作可被看作“订阅者”(也就是观察者)
- 订单取消类型可被看作是“主题”(也就是被观察者)
- 不同子操作(“订阅者”)(观察者)订阅订单取消类型(“主题”)(被观察者)
- 订单取消类型(“主题”)(被观察者)通知子操作(“订阅者”)(观察者)
业务流程图
我们通过梳理的文本业务流程得到了如下的业务流程图:
注:本文于单体架构背景探讨业务的实现过程,简单容易理解。 |
代码建模
「观察者模式」的核心是两个接口:
- “主题”(被观察者)接口
Observable
- 抽象方法
Attach
: 增加“订阅者” - 抽象方法
Detach
: 删除“订阅者” - 抽象方法
Notify
: 通知“订阅者”
- 抽象方法
- “订阅者”(观察者)接口
ObserverInterface
- 抽象方法
Do
: 自身的业务
- 抽象方法
订单逆向流的业务下,我们需要实现这两个接口:
- 具体订单取消的动作实现“主题”接口
Observable
- 子逻辑实现“订阅者”接口
ObserverInterface
伪代码如下:
// ------------这里实现一个具体的“主题”------------ |
同时得到了我们的UML图:
代码demo
package main |
代码运行结果:
[Running] go run "../easy-tips/go/src/patterns/observer/observer.go" |
结语
最后总结下,「观察者模式」抽象过程的核心是:
- 被依赖的“主题”
- 被通知的“订阅者”
- “订阅者”按需订阅“主题”
- “主题”变化通知“订阅者”
特别说明: |