设计模式-观察者模式(Observer Pattern)结构|原理|优缺点|场景|示例

发布于:2024-04-26 ⋅ 阅读:(25) ⋅ 点赞:(0)

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,允许一个或多个观察者对象订阅主题对象,当主题对象状态发生改变时,会通知所有已订阅的观察者对象,使得它们能够自动更新自己。

主要角色:

  1. Subject(抽象主题、被观察者)

    • 提供了一个注册和移除观察者的接口方法(如 registerObserver() 和 removeObserver())。
    • 定义了一个通知所有观察者的接口方法(如 notifyObservers())。
  2. ConcreteSubject(具体主题、具体被观察者)

    • 继承自抽象主题,是抽象主题的具体实现。
    • 维护一个观察者集合,并在自身状态改变时调用 notifyObservers() 方法通知所有观察者。
    • 可能会提供获取当前状态的方法。
  3. Observer(抽象观察者)

    • 定义了一个更新接口,所有具体的观察者都要实现这个接口。
    • 提供了当主题状态变化时需要执行的更新方法(如 update())。
  4. ConcreteObserver(具体观察者)

    • 是Observer接口的具体实现,包含了指向具体主题的引用。
    • 在接收到主题的通知后,通过调用 update() 方法响应状态的变化,更新自身的状态

工作流程:

  1. 观察者通过 registerObserver() 方法注册到被观察者。
  2. 当被观察者状态发生改变时,调用 notifyObservers() 方法。
  3. 被观察者遍历观察者集合,调用每个观察者的 update() 方法。
  4. 观察者在其 update() 方法中根据主题提供的信息或者直接访问主题的状态来进行相应的更新操作。

优缺点:

优点:

  1. 松耦合:观察者模式实现了主题(被观察者)和观察者之间的松耦合。主题不需要知道观察者的具体类型,只需要通过一个通用的接口进行通知,这有助于降低模块间的耦合度,提高系统的灵活性和可维护性。

  2. 扩展性好:增加新的观察者或删除已有的观察者都很方便,只需修改具体的观察者类,对主题和其他观察者没有影响。

  3. 响应式编程友好:观察者模式可以很容易地构建基于事件的系统,使得系统具备事件驱动能力,能够及时响应状态变化。

缺点:

  1. 如果观察者过多,每次主题状态变化时都需要通知所有的观察者,可能会造成效率低下,尤其是在大型系统中,通知机制可能成为瓶颈。

  2. 如果观察者和主题之间存在循环依赖,可能导致系统难以理解和调试。

  3. 如果没有良好的设计,可能会出现观察者忘记取消注册而导致内存泄露的情况。

  4. 当主题类的状态频繁变化时,会导致大量无谓的通知发送,加大系统的负载。

  5. 对于观察者来说,可能会因为不清楚主题的状态何时发生变化,而过度依赖于外部通知,不利于逻辑的清晰性和独立性。

 应用场景:

  • 在GUI编程中,按钮点击事件通知多个组件更新界面。
  • 数据绑定场景,数据模型变化时自动更新视图层。
  • 网络通信,服务器状态改变时通知所有订阅的客户端。
  • 日志框架中,日志级别变更时重新配置所有相关的日志处理器。

代码示例(以Java为例)

// 抽象观察者接口
public interface Observer {
    // 更新方法,当被观察者状态改变时会被调用
    void update(String message);
}

// 抽象被观察者接口
public interface Subject {
    // 注册观察者
    void registerObserver(Observer observer);
    // 移除观察者
    void removeObserver(Observer observer);
    // 通知所有观察者
    void notifyObservers(String message);
}

// 具体被观察者类
public class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    
    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

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

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

    // 被观察者的状态发生变化时,触发通知
    public void changeState(String newState) {
        System.out.println("Subject state changed to: " + newState);
        notifyObservers(newState);
    }
}

// 具体观察者类
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 the following message: " + message);
    }
}

// 测试类
public class Main {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        
        Observer observer1 = new ConcreteObserver("Observer 1");
        Observer observer2 = new ConcreteObserver("Observer 2");

        subject.registerObserver(observer1);
        subject.registerObserver(observer2);

        subject.changeState("New State");  // 改变被观察者状态,此时会触发通知
    }
}

在这个示例中,ConcreteSubject 类是具体的被观察者,它管理着一个观察者列表。当其状态改变时,会调用 notifyObservers() 方法通知所有已注册的观察者。ConcreteObserver 类是实现了 Observer 接口的具体观察者,当接收到 update() 方法调用时,会做出相应的反应。在 Main 类的测试代码中,我们创建了一个具体的被观察者对象,并添加了两个观察者,然后改变被观察者的状态,可以看到观察者都收到了通知并进行了更新。