行为型 - 1. 观察者模式

270 阅读3分钟

设计模式的分类:

  • 创建型设计模式主要解决“对象的创建”问题,将创建与使用解耦。
  • 结构型设计模式主要解决“类或对象的组合或组装”问题,将不同功能代码解耦。
  • 行为型设计模式主要解决的就是“类或对象之间的交互”问题,将不同的行为代码解耦。

观察者模式是一个比较抽象的模式,根据不同的应用场景和需求,观察者模式会对应不同的代码实现方式:有同步阻塞的实现方式,也有异步非阻塞的实现方式;有进程内的实现方式,也有跨进程的实现方式。

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")
}