观察者模式

在该模式中,当观察对象的状态发生变化时,会通知给观察者,观察者再对变化的状态进行处理。
类似你叫了一个外卖,你的订单是被观察对象,而提供给用户看的第三方(美团、饿了么)就是观察者。

该模式中几大roles

  • Subject (被观察对象) 订单
    这个家伙定义了注册观察者和删除观察者的方法,同时声明了“获取现在的状态”的方法。
  • ConcreteSubject (具体的观察对象)
    当自身状态发生改变时,会通知所有注册的观察者。
  • Observer (观察者)
    它定义了update方法负责接收来自Subject的状态变化的通知,然后进行处理。
    可以是抽象类,也可以是接口。
  • ConcreteObserver (具体的观察者)
    当它的update方法被调用后,会去获取要观察的对象的最新状态。

该模式的UML图:
图片说明

举个栗子:
比方有个携带着数字的对象,当它让这个数字+1产生变化时,观察者会将这个结果呈现,不同观察者会有不同的呈现形式。


代码实现:

//观察者接口
public interface Observer {
    public abstract void update(NumChange numChange);
}

public abstract class NumChange {
    private ArrayList<Observer> observers = new ArrayList<>(); //注册观察者们

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

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

    public void notifyObservers(){
        Iterator it = observers.iterator();
        while( it.hasNext() ){
            Observer o = (Observer)it.next();
            o.update(this);
        }
    }

    public abstract int getNumber();
    public abstract void execute();
}


//具体的观察对象
public class ConcreteNumChange extends NumChange{
    private int number = 5;
    public void execute(){
        number = number + 1;
        //数字发生变化,通知观察者们
        notifyObservers();
    }

    public int getNumber(){
        return this.number;
    }

}

//具体观察者
public class DigitObserver implements Observer{
    @Override
    public void update(NumChange numChange) {
        System.out.println(numChange.getNumber());
    }
}
public class GraphObserver implements Observer{
    @Override
    public void update(NumChange numChange) {
        System.out.println(numChange.getNumber()+"**********");
    }
}

//测试类
public class Main {
    public static void main(String[] args) {
        Observer observer1 = new DigitObserver();
        Observer observer2 = new GraphObserver();

        NumChange numChange = new ConcreteNumChange();
        numChange.addObserver(observer1);
        numChange.addObserver(observer2);
        numChange.execute();
    }
}

测试结果:
图片说明

优点

可替换性,可扩展性

  1. 由上面的代码,我们可以看出,具体观察对象对观察者的注册和删除这些公共方法被提取出来放在了抽象类中,这样能减少代码的冗余性,并且能扩展不同的具体观察对象。观察者接口也是同样的作用。
  2. 在将实例作为参数传到类中时,我们使用的是抽象类型或接口。比如具体的观察对象update方法传进了NumChange抽象类,它无需关心到底是哪个具体的观察对象。所以这个观察对象就有了可替换性

应用场景

  • Java.util包中有个Observer接口就是一种观察者模式。
  • MVC中的 Model 和 View 好比如 Subject 和 Observer。当Model中发生变化时, View只需要处理怎么将变化呈现即可。通常下, 一个Model对应多个View。