观察者是行为设计模式
GoF定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
场景
积分系统:消费积分记录、赚取积分记录,需要根据订单状态变化进行不同逻辑的处理。
消费积分记录
未付款->支付,进行消费积分核销
赚取积分记录
未付款->支付,进行赚取积分的冻结
发货->完成,进行赚取积分的解冻
怎么样?是不是觉得观察者模式非常适用
没错,观察者非常适用一对多依赖关系的场景,例如事件驱动系统、状态变化通知等。
实现
订单状态
go
const (
pendingOrderStatus = "pending" // 未支付状态
processingOrderStatus = "processing" // 支付状态
shipmentOrderStatus = "shipment" // 发货状态
completeOrderStatus = "complete" // 完成状态
cancelOrderStatus = "cancel" // 取消状态
)
接口
规范观察需要实现,通过这个可以收到观察对象的变化
go
type OrderStateObserver interface {
Update(subject *Subject)
}
订单
示例中需要观察的对象,主要是观察订单状态的变化
go
type Subject struct {
observers []OrderStateObserver // 观察者列表
stateOld string // 订单历史状态
stateNow string // 订单当前状态
}
// Attach 添加监听者
func (s *Subject) Attach(observer OrderStateObserver) {
s.observers = append(s.observers, observer)
}
// Detach 删除监听者
func (s *Subject) Detach(observer OrderStateObserver) {
for i, item := range s.observers {
if observer == item {
s.observers = append(s.observers[:i], s.observers[i+1:]...)
}
}
}
func (s *Subject) notify() {
for _, observer := range s.observers {
observer.Update(s)
}
}
func (s *Subject) GetStateNow() string {
return s.stateNow
}
func (s *Subject) GetStateOld() string {
return s.stateOld
}
func (s *Subject) SetSate(state string) {
s.stateOld = s.stateNow
s.stateNow = state
s.notify()
}
type OrderSubject struct {
Subject
}
func NewOrderSubject(state string) *OrderSubject {
return &OrderSubject{
Subject{stateNow: state},
}
}
Attach
添加观察者
Detach
删除观察者
订单的状态变化可以通过 notify
通知到观察者
积分使用记录
观察者,随订单状态变化,做出对应的逻辑
go
// ScoreUseRecordObserver 积分使用记录
type ScoreUseRecordObserver struct {
objectState string
}
func (c *ScoreUseRecordObserver) Update(subject *Subject) {
c.objectState = subject.GetStateNow()
// 此处可以进行积分使用记录的相关操作,略过,只是输出一行日志
fmt.Printf("积分使用记录, 执行观察者操作! 状态: %v -> %v\n", subject.GetStateOld(), c.objectState)
}
func NewScoreUseRecordObserver() *ScoreUseRecordObserver {
return &ScoreUseRecordObserver{}
}
积分获取记录
观察者,随订单状态变化,做出对应的逻辑
go
// ScoreGetRecordObserver 积分获取记录
type ScoreGetRecordObserver struct {
objectState string
}
func (c *ScoreGetRecordObserver) Update(subject *Subject) {
c.objectState = subject.GetStateNow()
// 此处可以进行积分获取记录的相关操作,略过,只是输出一行日志
fmt.Printf("积分获取记录, 执行观察者操作! 状态: %v -> %v\n", subject.GetStateOld(), c.objectState)
}
func NewScoreGetRecordObserver() *ScoreGetRecordObserver {
return &ScoreGetRecordObserver{}
}
订单状态变化
当状态发生变化时(如从 pending
变为 processing
),观察者会收到通知并执行相应的逻辑。
go
orderSubject := NewOrderSubject(pendingOrderStatus)
// 积分使用记录
scoreUseRecordObserver := NewScoreUseRecordObserver()
orderSubject.Attach(scoreUseRecordObserver)
// 积分获取记录
scoreGetRecordObserver := NewScoreGetRecordObserver()
orderSubject.Attach(scoreGetRecordObserver)
// 状态变成支付状态
orderSubject.SetSate(processingOrderStatus)
// 状态变成发货状态
orderSubject.SetSate(shipmentOrderStatus)
// 取消积分使用记录的监听
orderSubject.Detach(scoreUseRecordObserver)
// 状态变成完成状态
orderSubject.SetSate(completeOrderStatus)
完整代码
go
package main
// 观察者模式
import (
"fmt"
"testing")
const (
pendingOrderStatus = "pending" // 未支付状态
processingOrderStatus = "processing" // 支付状态
shipmentOrderStatus = "shipment" // 发货状态
completeOrderStatus = "complete" // 完成状态
cancelOrderStatus = "cancel" // 取消状态
)
type OrderStateObserver interface {
Update(subject *Subject)
}
// ScoreUseRecordObserver 积分使用记录
type ScoreUseRecordObserver struct {
objectState string
}
func (c *ScoreUseRecordObserver) Update(subject *Subject) {
c.objectState = subject.GetStateNow()
// 此处可以进行积分使用记录的相关操作,略过,只是输出一行日志
fmt.Printf("积分使用记录, 执行观察者操作! 状态: %v -> %v\n", subject.GetStateOld(), c.objectState)
}
func NewScoreUseRecordObserver() *ScoreUseRecordObserver {
return &ScoreUseRecordObserver{}
}
// ScoreGetRecordObserver 积分获取记录
type ScoreGetRecordObserver struct {
objectState string
}
func (c *ScoreGetRecordObserver) Update(subject *Subject) {
c.objectState = subject.GetStateNow()
// 此处可以进行积分获取记录的相关操作,略过,只是输出一行日志
fmt.Printf("积分获取记录, 执行观察者操作! 状态: %v -> %v\n", subject.GetStateOld(), c.objectState)
}
func NewScoreGetRecordObserver() *ScoreGetRecordObserver {
return &ScoreGetRecordObserver{}
}
type Subject struct {
observers []OrderStateObserver
stateOld string
stateNow string
}
// Attach 添加监听者
func (s *Subject) Attach(observer OrderStateObserver) {
s.observers = append(s.observers, observer)
}
// Attach 删除监听者
func (s *Subject) Detach(observer OrderStateObserver) {
for i, item := range s.observers {
if observer == item {
s.observers = append(s.observers[:i], s.observers[i+1:]...)
}
}
}
func (s *Subject) notify() {
for _, observer := range s.observers {
observer.Update(s)
}
}
func (s *Subject) GetStateNow() string {
return s.stateNow
}
func (s *Subject) GetStateOld() string {
return s.stateOld
}
func (s *Subject) SetSate(state string) {
s.stateOld = s.stateNow
s.stateNow = state
s.notify()
}
type OrderSubject struct {
Subject
}
func NewOrderSubject(state string) *OrderSubject {
return &OrderSubject{
Subject{stateNow: state},
}
}
func main() {
// 消费订单状态变化消息
// 这里略过
orderSubject := NewOrderSubject(pendingOrderStatus)
// 积分使用记录
scoreUseRecordObserver := NewScoreUseRecordObserver()
orderSubject.Attach(scoreUseRecordObserver)
// 积分获取记录
scoreGetRecordObserver := NewScoreGetRecordObserver()
orderSubject.Attach(scoreGetRecordObserver)
// 状态变成支付状态
orderSubject.SetSate(processingOrderStatus)
// 状态变成发货状态
orderSubject.SetSate(shipmentOrderStatus)
// 取消积分使用记录的监听
orderSubject.Detach(scoreUseRecordObserver)
// 状态变成完成状态
orderSubject.SetSate(completeOrderStatus)
}
总结
怎样?是不是觉得代码很优雅?
没错,观察者体现了对扩展开放、修改关闭设计原则。
1.订单状态和观察者之间通过接口交互,降低了依赖。
2.可以轻松添加新的观察者,而无需修改订单相关代码。
3.观察者可以动态地添加或移除。
观察者模式,可以比做科幻作品的穿越者,穿越者在历史事件发生的时候,在旁边记录着各种各样的人或事。
但设计模式中,观察者还可以随主体状态改变来做出对应的动作。