设计模式的分类:
- 创建型设计模式主要解决“对象的创建”问题,将创建与使用解耦。
- 结构型设计模式主要解决“类或对象的组合或组装”问题,将不同功能代码解耦。
- 行为型设计模式主要解决的就是“类或对象之间的交互”问题,将不同的行为代码解耦。
观察者模式是一个比较抽象的模式,根据不同的应用场景和需求,观察者模式会对应不同的代码实现方式:有同步阻塞的实现方式,也有异步非阻塞的实现方式;有进程内的实现方式,也有跨进程的实现方式。
1. 观察者模式的原理
观察者模式(Observer Design Pattern)也被称为发布订阅模式(Publish-Subscribe Design Pattern):在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
被依赖的对象叫作被观察者(Observable),依赖的对象叫作观察者(Observer)。在实际的项目开发中,这两种对象的称呼是比较灵活的,有各种不同的叫法,比如:Subject-Observer、Publisher-Subscriber、Producer-Consumer、EventEmitter-EventListener、Dispatcher-Listener。
2. 观察者模式的应用
观察者模式的应用场景非常广泛,小到代码层面的解耦,大到架构层面的系统解耦,再或者一些产品的设计思路,都有这种模式的影子,比如,邮件订阅、RSS Feeds。
使用消息队列是一种常见的跨进程的观察者模式实现方式。引入一个新的系统(消息队列),增加了维护成本。
它的好处也非常明显。在一般的实现方式中,观察者需要注册到被观察者中,被观察者需要依次遍历观察者来发送消息。而基于消息队列的实现方式,被观察者和观察者解耦更加彻底,两部分的耦合更小。被观察者完全不感知观察者,同理,观察者也完全不感知被观察者。被观察者只管发送消息到消息队列,观察者只管从消息队列中读取消息来执行相应的逻辑。
3. 观察者模式的代码实现
type Subject interface {
registerObservers(observer ...Observer)
removeObserver(observer Observer)
notifyObserves(message string)
}
type ConcreteSubject struct {
observers []Observer
}
func (c *ConcreteSubject) registerObservers(observer ...Observer) {
c.observers = append(c.observers, observer...)
}
func (c *ConcreteSubject) removeObserver(observer Observer) {
observers := c.observers
index := -1
length := len(observers)
for i, existObserver := range observers {
if existObserver.GetID() == observer.GetID() {
index = i
break
}
}
if index == -1 {
return
}
observers[index], observers[length-1] = observers[length-1], observers[index]
c.observers = observers[:length-1]
}
func (c *ConcreteSubject) notifyObserves(message string) {
for _, observer := range c.observers {
observer.Update(message)
}
}
type Observer interface {
Update(message string)
GetID() string
}
type CustomerObserver struct {
customID string
}
func NewCustomerObserver(id string) *CustomerObserver {
return &CustomerObserver{customID: "customer_" + id}
}
func (c *CustomerObserver) Update(message string) {
fmt.Printf("Sending email to customer %s for item %s\n", c.customID, message)
}
func (c *CustomerObserver) GetID() string {
return c.customID
}
type MerchantObserver struct {
merchantID string
}
func NewMerchantObserver(id string) *MerchantObserver {
return &MerchantObserver{merchantID: "merchant_" + id}
}
func (m *MerchantObserver) Update(message string) {
fmt.Printf("Phone call merchant %s for item %s\n", m.merchantID, message)
}
func (m *MerchantObserver) GetID() string {
return m.merchantID
}
// 客户端代码
func TestObserver(t *testing.T) {
customerObserver1 := &CustomerObserver{customID: "1"}
customerObserver2 := &CustomerObserver{customID: "2"}
merchantObserver1 := &MerchantObserver{merchantID: "1"}
merchantObserver2 := &MerchantObserver{merchantID: "2"}
subject := &ConcreteSubject{}
subject.registerObservers(customerObserver1, merchantObserver1)
subject.notifyObserves("Nike Shirt")
subject.registerObservers(customerObserver2, merchantObserver2)
subject.notifyObserves("Adidas Shoes")
subject.removeObserver(merchantObserver2)
subject.notifyObserves("Puma Pants")
}