【设计模式】观察者模式深度讲解

文章目录

概览

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当这个主题对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新。以下是关于观察者模式的详细介绍:

一、定义与特点

  1. 定义:观察者模式是一种对象行为模式,用于在对象之间建立一对多的依赖关系,以便当一个对象的状态发生变化时,所有依赖于它的对象都得到通知并被自动更新。
  2. 特点
    • 松耦合:主题和观察者之间通过抽象接口进行交互,使得它们可以独立演化而不影响彼此。
    • 一对多关系:一个主题可以有多个观察者,并且它们之间没有直接联系。
    • 可扩展性:可以随时增加新的观察者或删除现有观察者。
    • 实时性:实现了实时更新机制,当主题状态改变时能够即刻通知相关观察者。

二、角色与职责

在观察者模式中,通常包含以下几个角色:

  1. 抽象主题(Subject)角色:把所有观察者对象保存在一个集合里,提供注册和删除观察者对象的接口。
  2. 具体主题(ConcreteSubject)角色:实现抽象主题角色所提供的接口,当内部状态发生改变时,给所有注册的观察者发出通知。
  3. 抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。
  4. 具体观察者(ConcreteObserver)角色:实现抽象观察者角色所要求的更新接口,以便在得到主题的通知时更新自身的状态。

三、实现方式

观察者模式的实现方式多种多样,但从根本上说,必须包含观察者和被观察对象两个角色。通常,会定义一个观察者接口和一个主题接口,然后创建具体的观察者和主题类来实现这些接口。主题类中会维护一个观察者列表,并在状态改变时遍历通知所有观察者。

四、应用场景

观察者模式在实际应用中具有广泛的应用场景,包括但不限于以下几个方面:

  1. 事件处理:在图形用户界面(GUI)框架中,按钮的点击事件、窗口的打开和关闭事件等都可以使用观察者模式进行处理。
  2. 消息通知:在消息通知系统中,当发布者发布新消息时,订阅该消息的观察者将收到通知并进行相应的处理。
  3. 发布-订阅系统:观察者模式是发布-订阅模式的核心。当发布者发布新消息或事件时,所有订阅者都会收到通知并执行相应的操作。
  4. 实时数据更新:在需要实时更新数据的应用中,观察者模式可以用于将数据源与数据消费者连接起来。当数据源的数据发生变化时,观察者可以自动获取最新的数据并进行处理。
  5. 库和框架:许多编程库和框架使用观察者模式来支持插件和扩展。开发人员可以编写自定义观察者以响应库或框架中的事件或回调。
  6. 股票市场监测:股票市场应用程序可以使用观察者模式来监测股票价格变化,并将这些变化通知给投资者。
  7. 游戏开发:在游戏中,观察者模式可用于处理各种事件,如玩家输入、碰撞检测、角色状态变化等。
  8. 网络通信:在网络应用中,观察者模式可用于实现即时通信系统,其中用户之间的消息传递可以通过观察者模式来实现。

五、优缺点

  1. 优点

    • 降低了对象之间的耦合度:观察者模式使得主题和观察者之间通过抽象接口进行交互,从而降低了它们之间的耦合度。
    • 增强了系统的可扩展性:由于观察者模式采用了一对多的依赖关系,因此可以很方便地增加新的观察者。
    • 实现了实时更新机制:当主题状态改变时,能够即刻通知相关观察者,从而实现实时更新。
  2. 缺点

    • 如果观察者数量过多,可能会影响性能:因为主题需要遍历所有观察者并通知它们状态的变化,所以如果观察者数量过多,可能会影响系统的性能。
    • 主题只知道观察者发生了变化,但不知道具体发生了什么变化:这可能导致观察者无法做出准确的响应。

综上所述,观察者模式是一种非常有用的设计模式,它能够在对象之间建立松耦合的依赖关系,实现对象之间的动态联动和实时更新。然而,在使用时也需要注意其潜在的缺点和限制。

Java实现

在Java中,观察者模式可以通过接口和类来实现。以下是一个简单的观察者模式的Java代码示例,包括抽象主题(Subject)、具体主题(ConcreteSubject)、抽象观察者(Observer)和具体观察者(ConcreteObserver)。

首先,我们定义抽象主题接口Subject,它包含注册、删除和通知观察者的方法:

java 复制代码
// 抽象主题接口
public interface Subject {
    // 注册观察者
    void registerObserver(Observer observer);
    
    // 删除观察者
    void removeObserver(Observer observer);
    
    // 通知所有观察者
    void notifyObservers();
}

接着,我们定义抽象观察者接口Observer,它包含一个更新方法,用于在主题状态改变时更新观察者:

java 复制代码
// 抽象观察者接口
public interface Observer {
    // 更新观察者
    void update(String message);
}

然后,我们实现具体主题类ConcreteSubject,它实现了Subject接口,并维护一个观察者列表:

java 复制代码
import java.util.ArrayList;
import java.util.List;

// 具体主题类
public class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String state;

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(state);
        }
    }

    // 改变状态并通知观察者
    public void setState(String state) {
        this.state = state;
        notifyObservers();
    }

    // 获取状态(通常不需要,但为了完整性而提供)
    public String getState() {
        return state;
    }
}

最后,我们实现具体观察者类ConcreteObserver,它实现了Observer接口:

java 复制代码
// 具体观察者类
public class ConcreteObserver implements Observer {
    private String name;

    public ConcreteObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + " received message: " + message);
    }
}

现在,我们可以使用这些类来测试观察者模式:

java 复制代码
public class ObserverPatternDemo {
    public static void main(String[] args) {
        // 创建具体主题
        ConcreteSubject subject = new ConcreteSubject();

        // 创建具体观察者
        Observer observer1 = new ConcreteObserver("Observer 1");
        Observer observer2 = new ConcreteObserver("Observer 2");
        Observer observer3 = new ConcreteObserver("Observer 3");

        // 注册观察者
        subject.registerObserver(observer1);
        subject.registerObserver(observer2);
        subject.registerObserver(observer3);

        // 改变主题状态并通知观察者
        subject.setState("State has changed!");

        // 删除一个观察者
        subject.removeObserver(observer2);

        // 再次改变主题状态并通知剩余的观察者
        subject.setState("Another state change.");
    }
}

运行ObserverPatternDemo类的main方法,你将看到以下输出:

Observer 1 received message: State has changed!
Observer 2 received message: State has changed!
Observer 3 received message: State has changed!
Observer 1 received message: Another state change.
Observer 3 received message: Another state change.

注意,在第二次状态改变时,Observer 2不再收到通知,因为它已经被从观察者列表中删除了。这就是一个简单的Java观察者模式的实现。

Python实现

在Python中,观察者模式可以通过类和接口(在Python中通常使用抽象基类代替接口)来实现。以下是一个简单的Python实现观察者模式的示例。

首先,我们定义一个抽象基类Observer,它包含一个update方法,该方法将在主题状态改变时被调用:

python 复制代码
from abc import ABC, abstractmethod

class Observer(ABC):
    @abstractmethod
    def update(self, message: str):
        pass

接着,我们定义一个Subject类,它维护一个观察者列表,并提供注册、删除和通知观察者的方法:

python 复制代码
class Subject:
    def __init__(self):
        self._observers = []

    def register_observer(self, observer: Observer):
        self._observers.append(observer)

    def remove_observer(self, observer: Observer):
        self._observers.remove(observer)

    def notify_observers(self, message: str):
        for observer in self._observers:
            observer.update(message)

    # 通常还会有一个设置状态的方法,这里为了简单起见,直接提供notify_observers的调用
    def set_state(self, state: str):
        message = f"State has changed to: {state}"
        self.notify_observers(message)

现在,我们可以创建一个具体的观察者类,它继承自Observer抽象基类,并实现update方法:

python 复制代码
class ConcreteObserver(Observer):
    def __init__(self, name: str):
        self.name = name

    def update(self, message: str):
        print(f"{self.name} received message: {message}")

最后,我们可以编写一些代码来测试这个观察者模式:

python 复制代码
if __name__ == "__main__":
    # 创建主题
    subject = Subject()

    # 创建观察者
    observer1 = ConcreteObserver("Observer 1")
    observer2 = ConcreteObserver("Observer 2")
    observer3 = ConcreteObserver("Observer 3")

    # 注册观察者
    subject.register_observer(observer1)
    subject.register_observer(observer2)
    subject.register_observer(observer3)

    # 改变状态并通知观察者
    subject.set_state("New State")

    # 删除一个观察者
    subject.remove_observer(observer2)

    # 再次改变状态并通知剩余的观察者
    subject.set_state("Another New State")

运行上述代码,你将看到以下输出:

Observer 1 received message: State has changed to: New State
Observer 2 received message: State has changed to: New State
Observer 3 received message: State has changed to: New State
Observer 1 received message: State has changed to: Another New State
Observer 3 received message: State has changed to: Another New State

注意,在第二次状态改变时,Observer 2不再收到通知,因为它已经被从观察者列表中删除了。

这个示例展示了如何在Python中实现观察者模式。通过使用抽象基类和具体的观察者类,我们可以轻松地扩展和修改这个模式以适应不同的需求。

相关推荐
等一场春雨1 小时前
Java设计模式 五 建造者模式 (Builder Pattern)
java·设计模式·建造者模式
晚秋贰拾伍4 小时前
设计模式的艺术-代理模式
运维·安全·设计模式·系统安全·代理模式·运维开发·开闭原则
Cikiss4 小时前
「全网最细 + 实战源码案例」设计模式——简单工厂模式
java·后端·设计模式·简单工厂模式
新与5 小时前
设计模式:责任链模式——行为型模式
设计模式·责任链模式
等一场春雨5 小时前
Java设计模式 六 原型模式 (Prototype Pattern)
java·设计模式·原型模式
程序研14 小时前
JAVA之外观模式
java·设计模式
博一波17 小时前
【设计模式-行为型】观察者模式
观察者模式·设计模式
等一场春雨17 小时前
Java设计模式 十二 享元模式 (Flyweight Pattern)
java·设计模式·享元模式
rolt21 小时前
电梯系统的UML文档07
设计模式·产品经理·架构师·uml
等一场春雨1 天前
Java设计模式 十 装饰模式 (Decorator Pattern)
java·设计模式·装饰器模式