观察者模式

发布于:2025-07-02 ⋅ 阅读:(17) ⋅ 点赞:(0)

1. 问题背景

现在有三个类:机器类,工人类,订单类

机器类有一个属性叫 isBroken,类型为boolean,其值为false时,代表机器正常,工人和订单都不受影响

但是当其值为true时,工人需要去进行维修,同时订单状态也会设置为异常

也就是说,当机器类的状态变为异常的一瞬间,立马通知订单、工人进行相应的响应,比如说订单状态应该变为异常,工人状态应该变为维修中等等

2. 解决方案

2.1 轮询

在不了解观察者设计模式的时候你可能会想到通过轮询的方式进行,也就是说订单和工人,每10s去查询一次机器的状态,如果机器状态改变,那么就进行相应的业务逻辑

这样一定程度上可以解决问题,但是有几个明显的缺陷

  1. 每10s一次,性能肯定要受到影响

  2. 消息也不及时,根本没办法保证消息及时更新

2.2 硬通知

机器状态的改变,一定有一个函数去修改它的状态,那么我只需要在修改它 is Broken为true的时候,同时进行工人的业务逻辑以及订单的业务逻辑不就好了吗?

这样其实完全可以解决问题,但是也有几个缺陷

  1. 如果你要通知的对象只有工人和订单两个这倒是没问题,两行代码分别调用订单的业务逻辑函数和工人的业务逻辑函数即可,那如果有一万个你要通知的对象怎么办

  2. 耦合性太高,工人的业务逻辑以及订单的业务逻辑,出现在了机器里面,不方便维护,也不可读,甚至不方便修改、维护、扩展

2.3 观察者模式

观察者模式是一种通过发布-订阅的方式,解耦了被观察者(机器类)与观察者(工人类和订单类)之间的关系,使得一个对象(机器类的is Broken)状态变化时,可以自动通知所有需要关注这个变化的类(工人类和订单类)进行相应的更新或处理。

观察者模式的关键在于将通知机制从具体的业务逻辑中分离出来,这样当机器的 isBroken 状态变化时,机器类本身不需要知道如何处理工人和订单的逻辑,只需要通知工人类和订单类机器状态改变了,然后他们自己执行自己的业务逻辑。

3. 手搓代码环节

3.1 代码结构

image.png

3.2 Subject

主题是Machine类的原型,任何一个需要通知其他类进行变化的都需要以上三个方法,所以提出来成为接口,分别是添加观察者,移除观察者,通知所有观察者

package subject;

import observer.Observer;

public interface Subject {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

3.3 Machine

Machine继承上面的主题,并且实现了三个接口,并且有自己的属性isBroken,并提供了get、set方法

package subject;

import observer.Observer;

import java.util.ArrayList;
import java.util.List;

public class Machine implements Subject {
    private final List<Observer> observers = new ArrayList<>();
    private boolean isBroken = false;


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

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

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

    public void setBroken(Boolean isBroken)  {
        this.isBroken = isBroken;
        if (isBroken) {
            notifyObservers();
        }
    }

    public boolean getIsBroken() {
        return isBroken;
    }
}

3.3 Observe

每个观察者接受到消息发生变化以后,都需要处理自己的业务逻辑,所以提出来成为方法

package observer;

public interface Observer {
    void receiveNotification();
}

3.4 Worker

package observer;

import subject.Machine;

public class Worker implements Observer {
    private Machine machine;
    public Worker(Machine machine) {
        this.machine = machine;
        machine.addObserver(this);
    }

    @Override
    public void receiveNotification() {
        System.out.println("工人要去维修机器咯");
    }
}

3.5 Order

package observer;

import subject.Machine;

public class Order implements Observer {
    private Machine machine;
    public Order(Machine machine) {
        this.machine = machine;
        machine.addObserver(this);
    }

    @Override
    public void receiveNotification() {
        System.out.println("订单状态异常咯");
    }
}

3.6 Main

package app;


import observer.Order;
import observer.Worker;
import subject.Machine;

public class Main {
    public static void main(String[] args) {
        // 创建机器、工人和订单对象
        Machine machine = new Machine();
        Worker worker = new Worker(machine);
        Order order = new Order(machine);

        // 模拟机器正常运行
        for (int i = 1; i <= 10; i++) {
            System.out.println(machine.getIsBroken());
        }


        System.out.println("机器损坏");
        machine.setBroken(true);  // 机器损坏,工人和订单会被通知并作出反应
    }
}

4. 总结

运行截图

image.png