史上最易懂的观察者和被观察者模式——Java自带Observer,Observable类讲解

这几天review公司的代码,在查资料的过程中发现Java SDK中竟然自带了Observer和Observable类,有点出乎我意料。下班之后带着好奇的心态,使用了一下,竟然发现还挺好用。在这里也写一篇博客来记录一下整个实践过程。

为了便于理解,先来讲个出版社和读者的故事吧:很久很久以前,有一家备受欢迎的出版社和一群忠实的读者,每次出版社的新书出版,读者们都会收到来信。后来,互联网时代到了,为了更好的服务读者,出版社编写了一套系统,每次新书发布,这套系统都会自动地给读者分发图书,读者朋友在收到书之后也都会向出版社报告。

那么这套系统是怎么实现的呢,我们来拆分一下需求:

首先是出版社,作为分发的主体,由于时刻被读者朋友们盯着,肯定是被观察者了,整个分发过程中作为信息源头,负责将图书信息分发给读者。

其次是读者朋友,作为接受信息的主体,时刻观察着出版社的动向,只要出版社新书发布,马上就会收到消息,并且还会给出版社一个收到图书的报告。在这里,把他们作为观察者Observer。

好了,故事讲完了,下面开始扒了猛干。

Talk is cheap,show me the code.先来贴个小代码

public class Reader implements Observer {

	@Override
	public void update(Observable o, Object arg) {
		// TODO Auto-generated method stub
		System.out.println("Observable:" +o.getClass()+ "get:" + arg.toString());
	}

}

这里的Observer就是Java原生的接口了,我们在使用的时候只需要实现里面的update方法即可,当数据更新的时候会由Observable类内部持有的对象进行回调,整个过程完全自动化。

下面再来看一下出版社吧

public class Publisher extends Observable {
	
	public void setData(){
		this.setChanged();
	}
	
	
}

这里的Publisher继承了Observable类,通过观察源码我们不难发现,Observable中的setData是Protect修饰的,也就是说我们在SDK包的外部无法进行访问,为了能够使用这个改变通知数据的功能,我们在这里Override了setData方法,并且调用了setChanged方法来来改变相应的数据开关,至于什么是数据开关,大家先不用关心,在通知数据改变的过程中会交由父方法进行检查。

好了,现在基础类写好了,让我们的系统跑起来

public class ObserverTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Publisher publisher = new Publisher();
		Reader reader1 = new Reader();
		Reader reader2 = new Reader();
		publisher.addObserver(reader1);
		publisher.addObserver(reader2);
		publisher.setData();
		publisher.notifyObservers("收到图书");
		System.out.println("ObserverCount:" + publisher.countObservers());
	}
}

在上面的代码中我们一共做了以下几件事:

  1. 创建了一个出版社对象
  2. 找来了两名热心读者
  3. 把热心读者加入了出版社关怀,以便在出版社发出消息的时候这两名读者能够收到消息
  4. 出版社马上有了动作,新书出版了,出版社扳动了消息开关,准备推送消息。
  5. 出版社做出了具体的消息推送动作:告诉读者,如果你们收到消息,就告诉我一下:收到图书
  6. 最后出版社统计了一下读者人数。

让我们来看一下最后到底发生了什么吧:

Observable:class observerTest.Publisherget:收到图书
Observable:class observerTest.Publisherget:收到图书
ObserverCount:2

看,读者们收到了图书,并且向出版社做出了回应,一次完美的图书发布过程就此完毕。

到了这里,故事也就讲完了。投过故事,我们回头来想一下,这个故事的本质是什么?

可能就是观察者和被观察者设计模式吧,也就是我们俗称的回调。

以我所见,观察者和被观察者设计模式最核心的动作可能就是观察者的注册动作了,在这个故事中也就是出版商将读者加入关怀的动作。少了这个动作,可能任何人都没办法将二者联系起来,更别提什么回调了。

好了,故事讲完了,你明白这种设计模式了吗?

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
观察者模式是一种常见的设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。在这个模式中,被观察者对象通常称为主题(Subject),而观察者对象通常称为观察者(Observer)。 下面我们就以一个简单的天气预报系统为例来介绍观察者模式的使用。 首先,我们需要定义一个主题接口(Subject),它包含了添加、删除和通知观察者的方法: ```java public interface Subject { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObservers(); } ``` 然后,我们需要定义一个观察者接口(Observer),它包含了更新数据的方法: ```java public interface Observer { public void update(float temp, float humidity, float pressure); } ``` 接下来,我们需要定义一个具体的主题类(WeatherData),它实现了主题接口,并包含了一个列表来存储观察者对象,以及当前的温度、湿度和气压等数据: ```java import java.util.ArrayList; public class WeatherData implements Subject { private ArrayList<Observer> observers; private float temperature; private float humidity; private float pressure; public WeatherData() { observers = new ArrayList<Observer>(); } public void registerObserver(Observer o) { observers.add(o); } public void removeObserver(Observer o) { int i = observers.indexOf(o); if (i >= 0) { observers.remove(i); } } public void notifyObservers() { for (int i = 0; i < observers.size(); i++) { Observer observer = (Observer)observers.get(i); observer.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(); } // other WeatherData methods here } ``` 最后,我们需要定义一个具体的观察者类(CurrentConditionsDisplay),它实现了观察者接口,并在更新数据时打印出当前的温度、湿度和气压等信息: ```java public class CurrentConditionsDisplay implements Observer { private float temperature; private float humidity; private Subject weatherData; public CurrentConditionsDisplay(Subject weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } public void update(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; display(); } public void display() { System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity"); } } ``` 现在,我们可以创建一个天气预报系统,它包含了一个主题对象和一个观察者对象,并通过调用主题对象的方法来更新数据和通知观察者: ```java public class WeatherStation { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); weatherData.setMeasurements(80, 65, 30.4f); weatherData.setMeasurements(82, 70, 29.2f); weatherData.setMeasurements(78, 90, 29.2f); } } ``` 以上就是一个简单的观察者模式的例子,它可以让我们更好地理解和应用这个常见的设计模式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值