头图
观察者模式(Observer Pattern)属于行为型模式

概述

在 Java 中,一个对象的状态发生改变,就可能会影响到其他的对象,与之相关的对象可能也会联动的进行改变。

比如监听器机制,当具体的事件触发时,可以在创建的监听器中执行相关的逻辑。

观察者模式可以实现这样的功能,当对象发生改变时,观察者能够立即观察到并进行一些联动操作。

代码实现

自定义实现

这里以监听主体改变为例来介绍观察者模式:

1、定义观察者

/**
 * 观察者
 */
public interface Observer {

    /**
     * 更新操作
     */
    void update();

}

2、定义观察者实现类

/**
 * 观察者实现类
 */
public class ObserverImpl implements Observer {
    
    @Override
    public void update() {
        
        System.out.println("进行了修改");
    }
}

3、定义主体

/**
 * 主体
 */
public class Subject {

    /**
     * 观察者集合
     */
    private final Set<Observer> observerSet = new HashSet<>();

    /**
     * 添加观察者
     * @param observer 观察者
     */
    public void observe(Observer observer) {   
        observerSet.add(observer);
    }

    /**
     * 修改
     */
    public void modify() {
        
        // 当对象发生修改时,会通知所有的观察者,并进行方法回调
        observerSet.forEach(Observer::update);
    }

}

4、调用

// 主体
Subject subject = new Subject();
// 添加观察者
subject.observe(new ObserverImpl());
// 修改
subject.modify();

输出结果为:

进行了修改

可以发现,当主体调用修改方法时,添加的观察者观察到了变化,执行了操作。这就是观察者模式的自定义实现。

JDK自带实现

JDK 也提供了实现观察者模式的方式:

1、定义 JDK 实现的观察主体

/**
 * JDK实现的观察主体<br>
 * 继承 Observable 表示支持观察者
 */
public class Subject4Jdk extends Observable {

    /**
     * 修改
     */
    public void modify() {
        
        System.out.println("进行了修改");
        // 当对象修改后,需要 setChanged 来设定为已修改状态
        this.setChanged();
        // 使用 notifyObservers 方法来通知所有的观察者
        // 注意只有已修改状态下通知观察者才会有效,并且可以给观察者传递参数,这里传递了一个时间对象
        this.notifyObservers(new Date());   
    }

}

2、调用

// 主体
Subject4Jdk subject4Jdk = new Subject4Jdk();
// 添加观察者(Observable提供的方法)
subject4Jdk.addObserver((o, arg) -> System.out.println("监听到变化,并得到参数:" + arg));
// 进行修改操作
subject4Jdk.modify();

输出结果为:

进行了修改
监听到变化,并得到参数:Tue Aug 16 21:32:43 CST 2022

可以发现,JDK 自带的实现方式更为简洁,且功能更为强大,还能传递参数。

优缺点

优点

1、观察者和被观察者是抽象耦合的。

2、建立一套触发机制。

缺点

1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。

2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。

3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

使用场景

1、一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。

2、一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。

3、一个对象必须通知其他对象,而并不知道这些对象是谁。

4、需要在系统中创建一个触发链,A 对象的行为将影响 B 对象,B 对象的行为将影响 C 对象……,可以使用观察者模式创建一种链式触发机制。

注意事项

1、Java 中已经有了对观察者模式的支持类。

2、避免循环引用。

3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。


参考

https://www.bilibili.com/video/BV1u3411P7Na?p=28\&vd\_source=299f4bc123b19e7d6f66fefd8f124a03


天航星
1 声望0 粉丝

天河有尽后为涯,星海无边前作岸。