观察者模式:在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新

 

发布者(发布数据)——观察者1(接收数据)

发布者(发布数据)——观察者2(接收数据)

 

 

 

在这里举例:

发布者:比喻为 气象局,

观察者:墨迹天气(观察者1)、雅虎天气(观察者2)

 

气象局用仪器设备能采集到天气的 温度、湿度、气压

而墨迹天气、雅虎天气需要交钱成为会员,在气象局注册,气象局才会给他们俩推送数据

气象局采集的温度、湿度、气压一改变,就得通知墨迹天气、雅虎天气

如果墨迹天气不给气象局交钱,气象局就得把墨迹天气删掉,不再给他推送数据

(理解就好,不要在意语病)

 

代码来了:

1、发布者(气象局)推送天气数据需要实现的功能——接口

(1)能让各种天气软件注册为会员

(2)不交钱,就删除他们

(3)气象局实时采集到新的数据,就推送给会员们

package Observer;

public interface Subject {

	//注册观察者
	public void registerObserver(Observer o);
	
	//删除观察者
	public void removeObserver(Observer o);
	
	//当主题状态改变时,此方法被调用,来通知所有的观察者
	public void notifyObservers();
	
}

  

2、观察者得到的更新的数据——接口

package Observer;
/*
 * 所有观察者都必须实现update()方法,以实现观察者接口
 * 
 */
public interface Observer {

	//当气象观测值改变时,主题会把这些状态值当作方法的参数,传给观察者
	public void update(float temperature , float humidity, float pressure);
	
}

  

3、墨迹天气(观察者1)和雅虎天气(观察者2)都要显示从气象局得到的数据,这里单独提个接口,就是要让观察者必须实现display()方法,省的到时候忘了实现

package Observer;

public interface DisplayElement {

	//当布告板需要显示时,调用此方法
	public void display();
}

  

4、发布者(气象局)推送天气数据的功能实现类

package Observer;

import java.util.ArrayList;

public class WeatherData implements Subject{

	private ArrayList observers;	//观察者集合
	
	private float temperature;	//温度
	private float humidity;		//湿度
	private float pressure;		//气压
	
	public WeatherData(){
		observers = new ArrayList();
	}
	
	@Override
	public void registerObserver(Observer o) {
		observers.add(o);
	}

	@Override
	public void removeObserver(Observer o) {
		int i = observers.indexOf(o);
		if (i >= 0) {
			observers.remove(o);
		}
	}

	@Override
	public void notifyObservers() {
		for (int i = 0; i<observers.size(); i++) {
			Observer observer = (Observer) observers.get(i);
			observer.update(temperature, humidity, pressure);
		}
	}
	
	//数据改变,通知所有观察者
	public void setMeasurements(float temperature, float humidity, float pressure){
		this.temperature = temperature;
		this.humidity = humidity;
		this.pressure = pressure;
		measurementsChanged();
	}

	public void measurementsChanged(){
		notifyObservers();
	}
}

  

5、观察者(墨迹天气、雅虎天气等)接收数据并显示的功能实现类

package Observer;
/*
 * 观察者1:
 * 实现了Observer接口,可以从WeatherData对象中获得改变
 * 实现了DisplayElement接口,因为布告板都要展示数据,必须实现,防止忘记实现
 */
public class CurrentConditionsDisplay  implements Observer, DisplayElement{

	private float temperature;	//温度
	private float humidity;		//湿度
	private float pressure;		//气压
	private Subject weatherData;
	
	
	public CurrentConditionsDisplay(Subject weatherData){
		this.weatherData = weatherData;
		weatherData.registerObserver(this);	//注册当前观察者(this),Weather的ArrayList就添加了此观察者
	}
	
	@Override
	public void display() {
		System.out.println("温度:" + temperature + "\n" + "湿度:" + humidity + "\n" + "气压:" + pressure);
	}

	@Override
	public void update(float temperature, float humidity, float pressure) {
		this.temperature = temperature;
		this.humidity = humidity;
		this.pressure = pressure;
		display();	//值改变的时候就display()显示数据
	}

}

  

可以建立更多的观察者,display()不同的内容

 

6、Main方法:测试类

package Observer;

public class Main {

	public static void main(String[] args) {
		
		//建立WeatherData对象
		WeatherData weatherData = new WeatherData();
		
		//建立一个观察者(布告板),用来显示从主题获得的数据
		CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
		
		//可以建立更多的观察者,display()不同的内容
		
		weatherData.setMeasurements(50, 40, 30);
		//数据实时改变,就会输出最新的数据
		weatherData.setMeasurements(88, 77, 66);
	}

}

  

 

JDK自带的已实现的观察者模式

 

java.util包中提供的Observable类和Observer接口 实现了观察者模式。


Observer对象是观察者。


Observable对象是被观察者。



在被观察者Observable对象中调用setChanged()方法设置变化点。


通过notifyObservers();通知观察者 有变化了! 自动调用Observer对象的update()方法。


update(Observable o, Object arg)方法有俩个参数。


update方法的参数arg就是notifyObservers(arg);调用时传的参数(可以不传), 
o参数就是被观察者对象。


通过Observable对象调用addObserver(Observer os)来说明谁观察谁。参数是观察者。

 

 

 项目背景:项目中需要推送过车记录,推送给所有订阅者

 

1、被观察者(发布者,一个)

package com.zit.zVision.vehiclePassRecord.observer;

import java.util.Observable;
import com.zit.zVision.vehiclePassRecord.entity.VehiclePassRecord;

/**
 * 被观察者类(要推送的),继承这个类即可
 * 在被观察者Observable对象中调用setChanged()方法设置变化点。
 * 通过notifyObservers();通知观察者 有变化了! 自动调用Observer对象的update()方法。
 * @author 王晓东
 *
 */
public class VehiclePassRecordObservable extends Observable {

    private VehiclePassRecord vehiclePassRecord;
    
    public VehiclePassRecord getVehiclePassRecord() {
        return vehiclePassRecord;
    }

    public void setVehiclePassRecord(VehiclePassRecord vehiclePassRecord) {
        this.vehiclePassRecord = vehiclePassRecord;
    }

    public void push(VehiclePassRecord vehiclePassRecord) {
        this.vehiclePassRecord = vehiclePassRecord;
        //标识此对象已经被修改
        this.setChanged();
        //通知所有的观察者,相当于唤醒所有观察者的线程执行观察者的方法
        this.notifyObservers();
    }

}

 

 

2、观察者(订阅者,多个)

package com.zit.zVision.vehiclePassRecord.observer;

import java.util.Observable;
import java.util.Observer;

public class VehiclePassRecordObserver implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        //加一个判断,既可以防止强转失败,而且可以避免不是此观察者需要观察的被观察者进行方法
        if (o instanceof VehiclePassRecordObservable) {
            //强转获取到被观察者对象
            VehiclePassRecordObservable myObservable = (VehiclePassRecordObservable) o;
            /*
             * 此处接收到过车记录,做后续操作
             */
            System.out.println("被观察者改名了:" + myObservable.getVehiclePassRecord().toString());
        }
    }

}

 

 

3、测试类

 

package com.zit.zVision.vehiclePassRecord.observer;

import com.zit.zVision.vehiclePassRecord.entity.VehiclePassRecord;

/**
 * addObserver()添加订阅者
 * 调用push()方法,即可推送给所有订阅者
 * @author 0223000320
 *
 */
public class Test {

    public static void main(String[] args) {
        VehiclePassRecordObservable myObservable = new VehiclePassRecordObservable();
        //第1位观察者
        myObservable.addObserver(new VehiclePassRecordObserver());
        //第2位观察者
        myObservable.addObserver(new VehiclePassRecordObserver());
        //第3位观察者
        myObservable.addObserver(new VehiclePassRecordObserver());
        
        /*
         * 每次调用push()方法都会通知所有观察者
         */
        VehiclePassRecord vehiclePassRecord1 = new VehiclePassRecord();
        vehiclePassRecord1.setCphm("津A11111");
        myObservable.push(vehiclePassRecord1);
        
        VehiclePassRecord vehiclePassRecord2 = new VehiclePassRecord();
        vehiclePassRecord2.setCphm("津A22222");
        myObservable.push(vehiclePassRecord2);
    }
}

 

 

 

 

控制台输出:

 

 posted on 2017-09-20 10:44  布鲁布鲁sky  阅读(243)  评论(0编辑  收藏  举报