前言
观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。
在观察者模式中,有两种主要的角色:
- 观察者(Observer):观察者是一个接口或抽象类,它定义了一个更新的接口,使得被观察者在状态发生变化时可以通知观察者进行更新操作。
- 被观察者(Subject):被观察者是一个类,它维护了一组观察者对象,并提供了添加、删除和通知观察者的方法。当被观察者的状态发生变化时,它会通知所有的观察者进行更新操作。
被观察者对象在状态或内容(数据)发生变化时,会通知所有观察者对象,使它们能够做出相应的变化(如自动更新自己的信息)。
工作原理
- 观察者通过订阅被观察者,注册自己到被观察者的观察者列表中。
- 被观察者维护了一个观察者列表,当自身状态发生变化时,遍历观察者列表,调用每个观察者的更新方法。
- 观察者收到通知后,执行相应的更新操作,通常是从被观察者获取最新的状态信息,并进行相应的处理。
优点
- 解耦性: 观察者模式将观察者和被观察者解耦,使得它们可以独立地变化和复用。
- 可扩展性: 可以根据需要动态地增加和删除观察者,从而实现系统的灵活性和可扩展性。
- 通知机制: 观察者模式提供了一种简单的通知机制,使得被观察者可以在状态发生变化时通知所有的观察者。
缺点
- 可能引起循环依赖: 如果观察者和被观察者之间存在双向依赖关系,可能会导致循环依赖的问题。这样会使系统变得复杂,难以维护和理解。
- 通知顺序不确定: 观察者模式中观察者的通知顺序通常是不确定的,这可能会导致一些问题,特别是在多个观察者对同一事件进行响应时。
- 可能导致性能问题: 如果被观察者对象频繁地改变状态,会导致大量的通知操作,可能会影响系统的性能。
- 可能引发并发问题: 如果在多线程环境下使用观察者模式,可能会引发并发问题,需要额外的同步措施来保证线程安全。
- 过多的细粒度对象: 观察者模式可能会导致系统中存在大量的细粒度的观察者对象,这可能会增加系统的复杂性和内存消耗。
示例代码
Go
代码文件: observer/observer.go
package observer import "fmt" // 观察者接口 type Observer interface { Update(myapp MyAPP) } // 被观察者 type MyAPP struct { observers []Observer serverity int } func (m *MyAPP) GetServerity() int { return m.serverity } func (m *MyAPP) SetServerity(s int) { if s < 0 || s > 3 { fmt.Println("serverity must be an integer between 0 and 3") return } m.serverity = s fmt.Printf("Current severity is %d.\n", m.serverity) m.notify() } func (m *MyAPP) notify() { for _, observer := range m.observers { observer.Update(*m) } } func (m *MyAPP) AddObserver(observer Observer) { m.observers = append(m.observers, observer) } type Employee struct{} func (e *Employee) Update(myapp MyAPP) { if myapp.GetServerity() == 1 { fmt.Println("Employee: I'm notified!") } } type Manager struct{} func (m *Manager) Update(myapp MyAPP) { if myapp.GetServerity() == 2 { fmt.Println("Manager: I'm notified!") } } type Director struct{} func (d *Director) Update(myapp MyAPP) { if myapp.GetServerity() == 3 { fmt.Println("Director: I'm notified!") } }
代码文件: main.go
package main import ( "design-pattern-go/observer" ) func main() { myapp := &observer.MyAPP{} employee := &observer.Employee{} manager := &observer.Manager{} director := &observer.Director{} myapp.AddObserver(employee) myapp.AddObserver(manager) myapp.AddObserver(director) myapp.SetServerity(0) myapp.SetServerity(1) myapp.SetServerity(2) myapp.SetServerity(3) myapp.SetServerity(4) }
运行结果
$ go run main.go Current severity is 0. Current severity is 1. Employee: I'm notified! Current severity is 2. Manager: I'm notified! Current severity is 3. Director: I'm notified! serverity must be an integer between 0 and 3
Python
from abc import ABCMeta, abstractmethod class MyApp: """被观察者""" def __init__(self): self.__observers = [] self.__severity = 0 def get_severity(self): return self.__severity def set_severity(self, severity: int): if not isinstance(severity, int) or severity < 0 or severity > 3: raise ValueError("severity must be an integer between 0 and 3") self.__severity = severity print(f"current severity: {severity}") self.notify() def add_observer(self, observer): self.__observers.append(observer) def notify(self): """遍历观察者列表, 调用每个观察者的update方法""" for o in self.__observers: o.update(self) class Observer(metaclass=ABCMeta): """观察者基类""" @abstractmethod def update(self, myapp: MyApp): pass class Employee(Observer): def update(self, myapp: MyApp): if myapp.get_severity() == 1: print("An employee is notified") class Manager(Observer): def update(self, myapp: MyApp): if myapp.get_severity() == 2: print("A manager is notified") class Director(Observer): def update(self, myapp: MyApp): if myapp.get_severity() == 3: print("A director is notified") if __name__ == "__main__": myapp = MyApp() employee = Employee() manager = Manager() director = Director() myapp.add_observer(employee) myapp.add_observer(manager) myapp.add_observer(director) myapp.set_severity(1) myapp.set_severity(2) myapp.set_severity(3)
运行结果:
$ python .\observer.py current severity: 1 An employee is notified current severity: 2 A manager is notified current severity: 3 A director is notified