天天看点

观察者模式(Observer Pattern)——让你的对象知悉现状

目录

      • 概述
      • 观察者模式类图
      • 需要注意的东西
      • 从主题推push和拉push数据
      • 应用场景
        • 场景说明
        • 类图设计
        • 代码实现
      • 总结

概述

     观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新。这里改变的对象被称为主题(Subject)(也叫可观察者),它的依赖者称为观察者(Observer)。

观察者模式类图

观察者模式(Observer Pattern)——让你的对象知悉现状

需要注意的东西

  •      观察者和主题之间是松耦合方式结合,即主题不知道观察者的具体实现,只知道观察者所实现的接口。
  •      使用此模式时,可以从主题推(push)和拉(push)数据。(下面将会介绍)
  •      有多个观察者时,不能依赖特定的次序。
  •      java中有多种观察者模式的实现(多种暂时没找到),比较通用的是java.util.Observer(观察者)和java.util.Observable(主题)。

         需要注意的是,java.util.Observer是一个接口,而java.util.Observable是一个继承自Object的类。以下是jdk1.8中Observer和Observable的类图

    观察者模式(Observer Pattern)——让你的对象知悉现状

从主题推(push)和拉(push)数据

     通过上面的观察者模式类图可以知道,observer中的update方法主要是用于被主题用以更新的方法。推、拉数据时间上就是对update方法做控制。以下是推、拉数据的部分伪代码

/*
@param sub 主题,为了让观察者知道是哪一个主题通知它的 
@param arg 通知的内容,是notifyObservers()传入的数据对象
/*
public void update(Subject sub,Object arg){……}


//从主题推数据
/*
@param arg 通知的内容
*/
public void notifyObservers(Object arg){
    ```
    foreach(observe:Observers){
        ```
        observer.update(this,arg);
        ```
    }
    ```
}
//从主题拉数据
setChanged(){
    changed = true;
}
public void notifyObservers(Object arg){
    ```
    if(changed){
    // notify 只会在changed == true的时候通知观察者
        foreach(observe:Observers){
            ```
            observer.update(this,arg);
            ```
        }
        chaned=false;
    }
    ```
}

           

事实上在我看来推数据和拉数据最大的区别拉数据让观察者可以拥有从主题处选择数据的权利,而推数据,则不考虑观察者是否需要,一味地推送信息。

应用场景

场景说明

     以气象监测为例。其中包含三个部分是气象站(获取实际气象数据的物理装置)、WeatherData对象(追踪来自气象站的数据,并更新布告板)和布告板(显示目前天气状况给用户看)。以下将利用观察者模式去利用weatherData对象去获取数据并更新布告板。

类图设计

观察者模式(Observer Pattern)——让你的对象知悉现状

代码实现

package observer.api;

/**
 * <p>ClassName      Subject
 * <p>Description
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/7/12 21:56
 */
public interface Subject {

   /**
     * 注册观察者
     * @param observer
     */
    public void registerObserver(Observer observer);

    /**
     * 移除观察者
     * @param observer
     */
    public void removeObserver(Observer observer);

    /**
     * 通知观察者
     */
    public void notifyObservers();
}
           
package observer.api;

/**
 * <p>ClassName      Observer
 * <p>Description   观察者
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date            2017/7/12 21:57
 */
public interface Observer {

    /**
     * 主题用以更新观察者
     * @param temperature
     * @param humidity
     * @param pressure
     */
    public void update(float temperature,float humidity ,float pressure);
}

           
package observer.api;

/**
 * <p>ClassName      DisplayElement
 * <p>Description
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date            2017/7/12 21:59
 */
public interface DisplayElement {
    //布告板显示
    public void display();
}
           
package observer.impl;

import observer.api.Observer;
import observer.api.Subject;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * <p>ClassName      WeatherData
 * <p>Description
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date            2017/7/12 22:06
 */
public class WeatherData implements Subject {

    private ArrayList<Observer> observerList;
    private float               temperature; //温度
    private float               humidity; //湿度
    private float               pressure; //气压

    public WeatherData() {
        this.observerList = new ArrayList<Observer>();
    }

    public void registerObserver(Observer observer) {
        observerList.add( observer );
    }

    public void removeObserver(Observer observer) {
        int index = observerList.indexOf( observer );
        if (index >= ) {
            observerList.remove( index );
        }
    }

    public void notifyObservers() {
        Iterator<Observer> iterator = observerList.iterator();
        while (iterator.hasNext()) {
            iterator.next().update( temperature, humidity, pressure );
        }
    }

    /**
     * 得到更新值之后,通知观察者
     */
    public void measurementsChanged() {
        notifyObservers();
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }

}
           
package observer.impl;

import observer.api.DisplayElement;
import observer.api.Observer;
import observer.api.Subject;

/**
 * <p>ClassName      CurrentConditionsDisplay
 * <p>Description    采用推的方式更新数据
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/7/12 22:08
 */
public class CurrentConditionsDisplay implements DisplayElement, Observer {

    private float temperature; //温度
    private float humidity; //湿度
    private float pressure; //气压
    private Subject subject ; //当前通知的主题

    public CurrentConditionsDisplay(Subject subject) {
        this.subject = subject;
    }

    public void update(float temperature, float humidity, float pressure) {
        if (subject instanceof WeatherData) {
            // 如果是当前主题是WeatherData,才会更新布告板
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            display();
        }
    }

    public void display() {
        System.out.println(
                "天气信息更新啦!!!" +
                        "temperature=" + temperature +
                        ", humidity=" + humidity +
                        ", pressure=" + pressure );
    }


}
           
import observer.impl.CurrentConditionsDisplay;
import observer.impl.WeatherData;

/**
 * <p>ClassName      TestObserver
 * <p>Description     测试
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/7/12 22:21
 */
public class TestObserver {

    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentConditionsDisplay1 = new CurrentConditionsDisplay( weatherData );
        CurrentConditionsDisplay currentConditionsDisplay2 = new CurrentConditionsDisplay( weatherData );

        weatherData.registerObserver( currentConditionsDisplay1 );
        weatherData.setMeasurements( f,f,f );
        weatherData.registerObserver( currentConditionsDisplay2 );
        weatherData.setMeasurements( f,f,f );
        weatherData.removeObserver( currentConditionsDisplay1 );
        weatherData.setMeasurements( f,f,f );
    }
}
           

运行结果

观察者模式(Observer Pattern)——让你的对象知悉现状

总结

     第一次写正式技术博客,参考了很多大牛写设计模式学习笔记的逻辑。在写博客时,会根据自己对书本的不了解,而去查各种资料,在查资料时,又会get很多东西。

     好好学习,天天向上。诸君,切记持之以恒!

继续阅读