观察者模式:在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新
发布者(发布数据)——观察者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);
}
}
控制台输出: