行为设计模式之Observer(观察者)

发布于:2025-06-12 ⋅ 阅读:(27) ⋅ 点赞:(0)

行为设计模式之Observer(观察者)

前言:
一对多情况,当一个对象发生改变,所有依赖它的对象都会改变。
1.比如rbac权限系统,给一个用户设置成超级管理员权限角色,在子系统检测到该用户为超级管理员角色,会同步到所有子系统的子系统
2.中间件 比如rabbit 广播订阅模式,生产者发送消息到中间件,所有消费者绑定中间件topic的都会接收到消息。
3.游戏中比如游戏人物死亡,吃了加血包,所有技能该加技能加技能,加血加血
4.告警系统生产环境,某个指标异常,会有日志采集系统、短信服务系统…都会记录异常

摘要:
Observer(观察者)模式定义对象间一对多的依赖关系,当被观察者状态改变时,自动通知所有观察者。适用于RBAC权限同步、消息队列(如RabbitMQ)、游戏状态更新、监控报警等场景。结构包含Subject(目标)、Observer(观察者)及具体实现类,通过注册/通知机制实现解耦。典型应用包括:GUI事件处理、MVC数据同步、发布订阅系统、库存监控、游戏开发等。代码示例展示了Java实现,其中ConcreteSubject维护观察者列表并在状态变更时触发通知,ConcreteObserver更新自身状态与目标一致。该模式的核心优势是动态联动与低耦合。

1)意图

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知并被自动更新。

2)结构

在这里插入图片描述

其中:

  • Subject(目标)知道它的观察者,可以有任意多个观察者观察同一个目标;提供注册和删除观察者对象的接口。
  • Observer(观察者)为那些在目标发生改变时需活得通知的对象定义一个更新接口。
  • ConcreteSubject(具体目标)将有关状态存入各ConcreteSubject 对象;当它的状态发生改变时,向它的各个观察者发出通知。
  • ConcreteObserver(具体观察者)维护一个指向 ConcreteSubject 对象的引用;存储有关与目标的状态保持一致;实现Observer 的更新接口,以使自身状态与目标的状态保持一致。

3)适应性

Observe 模式适用于:

  • 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两者封装在独立的对象中以使它们可以各自独立地改变和复用(了解)
  • 当一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变时。
  • 当一个对象必须通知其他的对象,而它又不能假定其他对象是谁,既不希望这些对象是紧耦合的。
import java.util.ArrayList;
import java.util.List;

/**
 * @author psd 行为设计模式之观察者模式
 */
public class ObserverPattern {
    public static void main(String[] args) {
        /**
         * 被观察者
         */
        Subject subjectA = new ConcreteSubject("南京");

        Observer observerB = new ConcreteObserver("马鞍山",subjectA);
        Observer observerC = new ConcreteObserver("芜湖",subjectA);
        Observer observerD = new ConcreteObserver("蚌埠",subjectA);
        Observer observerE = new ConcreteObserver("合肥",subjectA);

        subjectA.setState("跟南哥混 三天吃九顿");
    }
}

/**
 * 被观察者接口
 */
interface Subject{

    /**
     * 添加观察者
     * @param observer
     */
    void attach(Observer observer);

    /**
     * 删除观察者
     * @param observer
     */
    void detach(Observer observer);

    /**
     * 状态改变后,通知所有观察者
     */
    void nofity();

    /**
     * 设置状态【改变状态】
     * @param state
     */
    void setState(String state);

    /**
     * 获取状态
     * @return
     */
    String getState();
}

class ConcreteSubject implements Subject{

    private String cityName;

    private String state;

    private List<Observer> observers;

    public ConcreteSubject(String cityName) {
        this.cityName = cityName;
        state = "谁是南哥";
        observers = new ArrayList<>();
    }

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

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

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

    @Override
    public void setState(String state) {
        this.state = state;
        System.out.println(cityName + "的状态发生了改变,变化后的状态是:" + state);
        nofity();
    }

    @Override
    public String getState() {
        return state;
    }
}

/**
 * 观察者接口
 */
interface Observer{
    /**
     * 状态改变后,更新
     */
    void update();
}

/**
 * 具体观察者类
 */
class ConcreteObserver implements Observer{

    private String cityName;
    private String state;
    private Subject subject;
    public ConcreteObserver(String cityName,Subject subject){
        this.cityName = cityName;
        this.subject = subject;
        subject.attach(this);
        state = subject.getState();
    }

    @Override
    public void update() {
        System.out.println(cityName + " 收到了通知。");
        // 让当前观察者的状态和目标的状态保持一致
        state  = subject.getState();
        System.out.println(cityName + " 状态为:" + state);
    }
}

在这里插入图片描述

4)以下是 Observer 模式的一些典型使用场景:

1、事件驱动系统 / GUI 编程:

场景描述: 这是最经典的应用场景。例如,一个按钮(被观察者)被点击时,需要通知多个执行不同操作的监听器(观察者),如保存数据、刷新界面、记录日志等。

模式作用: 按钮不需要知道具体有哪些监听器存在,只需要在点击时发出通知。监听器自行注册到按钮上,并在收到通知后执行各自的逻辑。实现了用户界面组件(按钮)与业务逻辑(监听器)的解耦。

2、数据模型与视图的同步 (MVC/MVP/MVVM 中的核心机制):

场景描述: 在 MVC 等架构中,数据模型(Model - 被观察者)的状态发生变化(如用户数据更新、股票价格变动)时,需要自动更新依赖于该模型的多个视图(View - 观察者)。

模式作用: 模型作为被观察者,维护一个观察者列表(通常是视图或视图模型)。当模型数据改变时,它通知所有注册的视图。视图收到通知后,从模型中获取最新数据并更新自身显示。这确保了多个视图能实时反映模型的最新状态。

3、发布-订阅系统的基石:

场景描述: 消息队列、事件总线等发布-订阅(Pub/Sub)系统本质上是对 Observer 模式的扩展和泛化。发布者(Publisher - 类似 Subject)发布消息到特定主题(Topic/Channel),订阅了该主题的订阅者(Subscriber - 类似 Observer)会接收到消息。

模式作用: Observer 模式是 Pub/Sub 的核心思想。Subject 就是 Publisher,Observer 就是 Subscriber。通知机制通过中间的消息通道(主题)进行解耦,发布者和订阅者通常完全不知道对方的存在。适用于分布式系统、微服务间的异步通信、实时数据推送等。

4、监控和报警系统:

场景描述: 监控服务器(被观察者)的 CPU 使用率、内存占用、网络状态等指标。当某个指标超过阈值(状态改变)时,需要触发多种报警动作(观察者),如发送邮件、短信、记录到数据库、在控制台显示警告等。

模式作用: 监控服务器负责收集状态并在变化时发出通知。各种报警处理程序作为观察者注册到监控服务器上,收到通知后执行各自的报警逻辑。可以灵活地添加或移除报警方式,而不影响监控服务器本身。

5、库存或价格变化通知:

场景描述: 在电商系统中,当某个商品(被观察者)的库存数量发生变化(如补货、售罄)或价格调整时,需要通知多个相关方(观察者),如:

更新前端商品详情页显示。

触发给设置了“到货通知”用户的邮件/短信。

通知推荐系统重新计算推荐列表。

更新库存管理系统报表。

模式作用: 商品对象状态改变时通知所有注册的观察者。观察者根据自身职责(更新UI、发通知、更新报表)进行响应。

6、游戏开发:

场景描述: 游戏中角色(被观察者)的生命值(HP)发生变化时,需要通知多个系统(观察者):

UI 系统:更新屏幕上的血条。

音效系统:播放受伤或治疗音效。

成就系统:检查是否达成“濒死反击”、“满血通关”等成就。

存档系统:可能需要记录关键的生命值变化点。

模式作用: 角色对象只负责管理自身 HP 并在变化时广播通知。各个系统模块注册为观察者,独立处理 HP 变化事件,实现功能模块间的解耦。

7、文件系统监控:

场景描述: 监控一个目录(被观察者),当目录中的文件被创建、修改或删除(状态改变)时,需要通知多个处理程序(观察者),如:

自动备份新文件或修改过的文件。

更新文件索引。

触发病毒扫描。

发送变更通知给用户。

模式作用: 文件监控服务在检测到变化时发出通知。不同的文件处理程序作为观察者进行响应。

总结 Observer 模式适用场景的核心特征:

存在一对多的依赖关系: 一个对象(Subject)的状态变化需要影响多个其他对象(Observers)。

状态变化需要广播通知: 当 Subject 的状态发生有意义的改变时,需要主动告知所有依赖它的对象。

不希望紧密耦合: 希望 Subject 和 Observers 之间的依赖关系是松散的。Subject 不需要知道 Observer 的具体类型或实现细节,只需要知道它们实现了某个通知接口。Observer 可以自由地订阅或取消订阅通知。

动态添加/移除观察者: 需要在运行时灵活地添加新的 Observer 或移除不再需要的 Observer。

开闭原则: 可以很方便地添加新的 Observer 类来响应 Subject 的状态变化,而不需要修改 Subject 的代码(对扩展开放)。修改一个 Observer 通常不会影响其他 Observer 或 Subject(对修改封闭)。

简单来说,当你需要让一个对象的状态变化自动触发一系列其他对象的更新操作,并且希望这些对象之间保持松耦合关系时,Observer 模式就是一个非常合适的选择。 它有效地分离了“变化源”和“变化响应者”。

喜欢我的文章记得点个在看,或者点赞,持续更新中ing…


网站公告

今日签到

点亮在社区的每一天
去签到