设计模式之观察者模式

(一) 什么是观察者模式

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

(二) 观察者模式的四个角色

· 抽象主题角色:一个接口或抽象类,定义了主题的基本功能(添加,删除观察者,把更新信息发送给观察者).
· 抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
· 具体主题角色:一个具体的主题,在集体主题的内部状态改变时,向所有登记过的观察者发出通知。
· 具体观察者角色:实现抽象观察者接口,观察者必须注册具体主题,以便接收更新.

在这里插入图片描述

(三) 观察者模式应用场景

现在有一个气象站,很多气象软件都会获取气象站的数据来显示给自己的用户,并且在气象站更新数据时,气象软件会受到更新信息并更新自己的数据.

现在,让我们来构建观察者模式.在这里,气象站是一个主题,而气象软件则是观察者,观察气象站数据.
1, 定义一个抽象主题接口

public interface Observerable {
    //添加一个观察者
    public void registerObserver(Observer o);
    //删除一个观察者
    public void removeObserver(Observer o);
    //将更新信息发送给所有观察者
    public void notifyObserver();
}

2、定义一个抽象观察者接口

public interface Observer {
    //当气象观测值改变时,主题会把这些状态值当作方法的参数,传送给观察者。
    //当主题调用notifyObservers()方法时,观察者的update()方法会被回调。
    public void update(float temp, float humidity, float pressure);
}

3、定义主题者WeatherData,实现了Observerable接口,对Observerable接口的三个方法进行了具体实现,同时有一个List集合,用以保存注册的观察者,等需要通知观察者时,遍历该集合即可。

public class WeatherData implements Observerable {
    
    //记录该主题的观察者
    private List<Observer> observers = new ArrayList<Observer>();
    //气象数据
    private float temperature;
    private float humidity;
    private float pressure;
    
    /**
     * @Description:注册观察者
     * @param o
     */
    @Override
    public void registerObserver(Observer o) {
	//将观察者添加到注册表中
	observers.add(o);
    }

    /**
     * @Description:注销观察者
     * @param o
     */
    @Override
    public void removeObserver(Observer o) {
	
	int i = observers.indexOf(o);
	if(i>=0){
	    observers.remove(i);
	}
    }

    /**
     * @Description:把更新的信息发送给所有观察者
     */
    @Override
    public void notifyObserver() {
	//遍历所有观察者,把更新信息推给所有观察者
	for(int i=0;i<observers.size();i++){
	    Observer observer = observers.get(i);
	    observer.update(temperature, humidity, pressure);
	}
    }
 /**
     * @Description:气象站更新自己的信息
     * @param temperature
     * @param humidity
     * @param pressure
     */
    public void setMeasurements(float temperature, float humidity, float pressure) {
	this.temperature = temperature;
	this.humidity = humidity;
	this.pressure = pressure;
	//更新完自己的信息后,要推送给所有观察者
	notifyObserver();
    }
}

4 , 定义具体观察者,建立布告板.

public class CurrentConditionsDisplay implements Observer{
    private float temperature;
    private float humidity;
    private float pressure;
    private Observerable weatherData;
    
    //在创建观察者时需要主题对象,以用来注册或注销
    public CurrentConditionsDisplay(Observerable weatherData){
	this.weatherData = weatherData;
    }
    
    
    
    //根据主题--气象站的信息更新自己的信息
    public void update(float temp, float humidity, float pressure) {
	this.temperature = temp;
	this.humidity = humidity;
	this.pressure = pressure;
	display();
    }
    //显示信息
    public void display(){
	System.out.println("temperature:"+temperature+" ,humidity:"+humidity+" ,pressure:" +pressure);
    }
    
}

测试一下我们的观察者模式

public static void main(String[] args) {
	//创建一个气象站
	WeatherData weatherData = new WeatherData();
	//创建两个观察者,
	CurrentConditionsDisplay observer1 = new CurrentConditionsDisplay(weatherData);
	CurrentConditionsDisplay observer2 = new CurrentConditionsDisplay(weatherData);
	//注册观察者
	weatherData.registerObserver(observer1);
	weatherData.registerObserver(observer2);
	//气象站更新数据了
	weatherData.setMeasurements(1, 2, 3);
	System.out.println("------注销一个观察者-----------");
	//将一个观察者注销
	weatherData.removeObserver(observer1);
	//再次更新数据
	weatherData.setMeasurements(2, 3, 4);
    }

在这里插入图片描述

可以看到,当观察者在主题中注册之后就可以收到主题更新的信息,而一旦注销之后,就不会收到主题的信息.
但是有一个问题,那就是并不是所有的观察者都需要主题的所有信息,他们只想自己拉取他们想了解的那部分信息,而不是由主题将所有的信息都推给观察者.而且使用拉的方式获取信息会使得你的功能更容易扩展,就算以后主题又添加了一个属性,只需要设置相应的getter就可以.
下面,我们使用java内置的观察者模式来实现我们的功能

public class WeatherData2 extends Observable {
    private float temperature;
    private float humidity;
    private float pressure;
    //不用再记住观察者
    //private List<Observer> observers = new ArrayList<Observer>();
    
    public WeatherData2(){
	
    }
    
    /**
     * @Description:气象站更新自己的信息
     * @param temperature
     * @param humidity
     * @param pressure
     */
    public void setMeasurements(float temperature, float humidity, float pressure) {
	this.temperature = temperature;
	this.humidity = humidity;
	this.pressure = pressure;
	//更新完自己的信息后,要推送给所有观察者
	notifyObservers();
    }
    
    
    //生成getter方法,以让观察者拉取
    
    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }
        
}
//实现java内置观察者java.util.Observer;
public class CurrentConditionsDisplay2 implements Observer {
    Observable weatherData;
    private float temperature;
    private float humidity;
    
  //在创建观察者时需要主题对象,以用来注册或注销
    public CurrentConditionsDisplay2(Observable weatherData){
	this.weatherData = weatherData;
	//由观察者自己决定是否关注主题
	weatherData.addObserver(this);
    }
    
    //由自己来拉取所需要的信息
    public void update(Observable o, Object arg) {
	WeatherData2 weatherData2 = (WeatherData2)o;
	this.temperature = weatherData2.getTemperature();
	this.humidity = weatherData2.getHumidity();
	display();
    }
    //显示信息
    public void display(){
	System.out.println("temperature:"+temperature+" ,humidity:"+humidity);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值