zoukankan      html  css  js  c++  java
  • 观察者模式

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

    发布者(发布数据)——观察者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 + "
    " + "湿度:" + humidity + "
    " + "气压:" + 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);
        }
    }

    控制台输出:

  • 相关阅读:
    Oracle中优化SQL的原则(转贴)
    Oracle的分页查询
    Oracle中存储过程和Sql语句的优化重点
    oracle中sql语句的优化
    Oracle中优化SQL的原则(转贴)
    Oracle group by 用法实例详解
    Oracle中group by用法
    一本超越期待的 C++ 书——简评《Boost程序库完全开发指南:深入C++“准”标准库》
    以小见大——那些基于 protobuf 的五花八门的 RPC(2)
    BizTalk请求JAVA的Web Service报错
  • 原文地址:https://www.cnblogs.com/Donnnnnn/p/7560227.html
Copyright © 2011-2022 走看看