[设计模式]行为型模式-观察者模式

简介: [设计模式]行为型模式-观察者模式

前言

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。

在观察者模式中,有两种主要的角色:

  • 观察者(Observer):观察者是一个接口或抽象类,它定义了一个更新的接口,使得被观察者在状态发生变化时可以通知观察者进行更新操作。
  • 被观察者(Subject):被观察者是一个类,它维护了一组观察者对象,并提供了添加、删除和通知观察者的方法。当被观察者的状态发生变化时,它会通知所有的观察者进行更新操作。

被观察者对象在状态或内容(数据)发生变化时,会通知所有观察者对象,使它们能够做出相应的变化(如自动更新自己的信息)。

工作原理

  1. 观察者通过订阅被观察者,注册自己到被观察者的观察者列表中。
  2. 被观察者维护了一个观察者列表,当自身状态发生变化时,遍历观察者列表,调用每个观察者的更新方法。
  3. 观察者收到通知后,执行相应的更新操作,通常是从被观察者获取最新的状态信息,并进行相应的处理。

优点

  1. 解耦性: 观察者模式将观察者和被观察者解耦,使得它们可以独立地变化和复用。
  2. 可扩展性: 可以根据需要动态地增加和删除观察者,从而实现系统的灵活性和可扩展性。
  3. 通知机制: 观察者模式提供了一种简单的通知机制,使得被观察者可以在状态发生变化时通知所有的观察者。

缺点

  1. 可能引起循环依赖: 如果观察者和被观察者之间存在双向依赖关系,可能会导致循环依赖的问题。这样会使系统变得复杂,难以维护和理解。
  2. 通知顺序不确定: 观察者模式中观察者的通知顺序通常是不确定的,这可能会导致一些问题,特别是在多个观察者对同一事件进行响应时。
  3. 可能导致性能问题: 如果被观察者对象频繁地改变状态,会导致大量的通知操作,可能会影响系统的性能。
  4. 可能引发并发问题: 如果在多线程环境下使用观察者模式,可能会引发并发问题,需要额外的同步措施来保证线程安全。
  5. 过多的细粒度对象: 观察者模式可能会导致系统中存在大量的细粒度的观察者对象,这可能会增加系统的复杂性和内存消耗。

示例代码

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
相关文章
|
4月前
|
设计模式 网络协议 Java
【设计模式】【行为型模式】状态模式(State)
一、入门 什么是状态模式? 状态模式(State Pattern)是一种行为设计模式,允许对象在其内部状态改变时改变其行为,使其看起来像是改变了类。状态模式的核心思想是将对象的状态封装成独立的类,并将
190 16
|
4月前
|
设计模式 算法 前端开发
【设计模式】【行为型模式】职责链模式(Chain of Responsibility)
一、入门 什么是职责链模式? 职责链模式是一种行为设计模式,它允许你将请求沿着一条链传递,直到有对象处理它为止。每个对象都有机会处理请求,或者将其传递给链中的下一个对象。 为什么需要职责链模式? 使用
145 16
|
4月前
|
设计模式 存储 Java
【设计模式】【行为型模式】备忘录模式(Memento)
一、入门 什么是备忘录模式? 备忘录模式(Memento Pattern)是一种行为设计模式,用于在不破坏封装性的前提下,捕获并外部化一个对象的内部状态,以便在需要时恢复该状态。它通常用于实现撤销操作
145 8
|
9月前
|
设计模式 存储 供应链
前端必须掌握的设计模式——观察者模式
观察者模式(Observer Pattern)是一种行为型设计模式,实现了一种订阅机制。它包含两个角色:**观察者**(订阅消息、接收通知并执行操作)和**被观察者**(维护观察者列表、发送通知)。两者通过一对多的关系实现解耦,当被观察者状态改变时,会通知所有订阅的观察者。例如,商店老板作为被观察者,记录客户的需求并在商品到货时通知他们。前端应用中,如DOM事件注册、MutationObserver等也体现了这一模式。
|
4月前
|
设计模式 消息中间件 Java
【设计模式】【行为型模式】命令模式(Command)
一、入门 什么是命令模式? 命令模式是一种行为设计模式,它将请求或操作封装为对象,从而使你可以用不同的请求对客户进行参数化,并支持请求的排队、记录、撤销等操作。 命令模式的核心是将“请求”封装为独立的
163 15
|
4月前
|
设计模式 算法 搜索推荐
【设计模式】【行为型模式】策略模式(Strategy)
一、入门 什么是策略模式? 策略模式是一种行为设计模式,允许在运行时选择算法或行为。它将算法封装在独立的类中,使得它们可以互换,而不影响客户端代码。 为什么需要策略模式? 策略模式的主要目的是解决算法
100 14
|
4月前
|
设计模式 数据采集 算法
【设计模式】【行为型模式】模板方法模式(Template Method)
一、入门 1.1、什么是模板方法模式? 模板模式(Template Method Pattern)是一种行为设计模式,它定义了一个算法的框架,并允许子类在不改变算法结构的情况下重新定义算法的某些步骤。
128 13
|
4月前
|
设计模式 Java 编译器
【设计模式】【行为型模式】解释器模式(Interpreter)
一、入门 什么是解释器模式? 解释器模式(Interpreter Pattern)是一种行为设计模式,用于定义语言的语法表示,并提供一个解释器来处理该语法。它通常用于需要解释和执行特定语言或表达式的场
89 11
|
4月前
|
设计模式 存储 JavaScript
【设计模式】【行为型模式】迭代器模式(Iterator)
一、入门 什么是迭代器模式? 迭代器模式(Iterator Pattern)是一种行为设计模式,它提供了一种顺序访问聚合对象中元素的方法,而不需要暴露其底层表示。迭代器模式将遍历逻辑从聚合对象中分离出
106 11
|
4月前
|
设计模式 XML JSON
【设计模式】【行为型模式】访问者模式(Visitor)
一、入门 什么是访问者模式? 访问者模式(Visitor Pattern)是一种行为设计模式,允许你将算法与对象结构分离。通过这种方式,可以在不改变对象结构的情况下,向对象结构中的元素添加新的操作。
133 10