观察者模式

82 阅读2分钟

观察者模式主要是为了降低对象之间的耦合度

在对象之间定义一对多的依赖,当一的一方状态发生改变的时候,依赖一的一方(多的一方)就会收到通知,并进行自动更新

Pasted image 20221128223139

此时up主就是被观察者,而订阅的人就是观察者,一旦被观察者(主题)状态发生改变,相应的观察者也就会就行改变

经典问题:气象站问题
当气象站监测的温度、湿度、压强等信息发生改变时,相应的看板也要发生信息的改变

代码实现

public interface Subject {  //主题,也就是被观察者
  
    void registerObserver(Observer observer);  
  
    void removeObserver(Observer observer);  
  
    void notifyObserver();  
}

//气象台
public class WeatherData implements Subject{  
  
    private float temperature;  
    private float humidity;  
    private float pressure;  
  
    private List<Observer> observers;  
  
    public WeatherData() {  
        this.observers = new ArrayList<>();  
    }  
  
    @Override  
    public void registerObserver(Observer observer) {  
        observers.add(observer);  
    }  
  
    @Override  
    public void removeObserver(Observer observer) {  
        Iterator<Observer> iterator = observers.iterator();  
        while (iterator.hasNext()){  
            Observer next = iterator.next();  
            if(next.equals(observer)){  
                iterator.remove();  
                break;  
            }  
        }  
    }  
  
    @Override  
    public void notifyObserver() {  
        for (Observer observer : observers) {  
            observer.update(temperature,humidity,pressure);  
        }  
    }  
  
    public void measurementsChanged(){  
        notifyObserver();  
    }  
  
    public void setMeasurements(float temperature,float humidity,float pressure){  
        this.temperature = temperature;  
        this.humidity = humidity;  
        this.pressure = pressure;  
        measurementsChanged();  
    }  
}

//观察者接口
public interface Observer {  
  
    void update(float temp,float humidity,float pressure);  //发生变化时调用的方法
  
}

//面板
public class CurrentConditionsDisplay implements Observer,DisplayElement{  
  
    private float temperature;  
    private float humidity;  
    private Subject subject;  
    
	//注册
    public CurrentConditionsDisplay(Subject subject) {  
        this.subject = subject;  
        subject.registerObserver(this);  
    }  
  
    @Override  
    public void display() {  
        System.out.println("当前天气面板:温度:"+temperature+"   湿度:"+humidity);  
    }  
  
    @Override  
    public void update(float temp, float humidity, float pressure) {  
        this.temperature = temp;  
        this.humidity = humidity;  
        display();  
    }  
}
  • 当气象台的监测到温度发生变化时,调用measurementsChanged方法,主题会推送数据到观察者,并调用观察者发生数据变化后进行的操作
  • 当前的观察者方法是采用推送数据给观察者,也可采用观察则自己拉去的方法
  • jdk有内置的观察者模式

jdk观察者模式源码分析

public class Observable {  
    private boolean changed = false;//判断是否改变,可进行控制  
    private Vector<Observer> obs;  
  
    public Observable() {  
        obs = new Vector<>();  
    }  
  
	public synchronized void addObserver(Observer o) {  
        if (o == null)  
            throw new NullPointerException();  
        if (!obs.contains(o)) {  
            obs.addElement(o);  
        }  
    }  
  
    public synchronized void deleteObserver(Observer o) {  
        obs.removeElement(o);  
    }  

	//拉
    public void notifyObservers() {  
        notifyObservers(null);  
    }  

	//推
    public void notifyObservers(Object arg) {  
        Object[] arrLocal;  
  
        synchronized (this) {  
             if (!changed)  
                return;  
            arrLocal = obs.toArray();  
            clearChanged();  
        }  
  
        for (int i = arrLocal.length-1; i>=0; i--)  
            ((Observer)arrLocal[i]).update(this, arg);  
    }  
  
	public synchronized void deleteObservers() {  
        obs.removeAllElements();  
    }  
  
    protected synchronized void setChanged() {  
        changed = true;  
    }  
  
    protected synchronized void clearChanged() {  
        changed = false;  
    }  
  
    public synchronized boolean hasChanged() {  
        return changed;  
    }  
  
    public synchronized int countObservers() {  
        return obs.size();  
    }  
}

//观察者接口
public interface Observer {
	//o为被观察者对象,可以拉去数据
	//arg是推送过来的数据
    void update(Observable o, Object arg);  
}