观察者模式的本质:(触发联动)
当修改目标状态时就会触发相应的通知,然后会循环调用所有注册的观察者对象的相应方法。
观察者模式的应用场景:天气预报,许多网站,人等需要第一时间得知天气的变化,然后做各自的出行计划
定义:定义对象间的一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
(一个目标类,多个观察者(用来观察目标)当目标类发生变化时,可以通知到他的所有观察者。)统一通知,各自处理
原理:利用回调函数机制。 所有“观察者类”继承一个“接口”(如Observer),该接口中有一个方法(如,update())。将所有的观察者增添到“目标类”的“链表”中,当目标类的状态发生改变时,目标类可以遍历链表中的所有观察者,调用其update通知到所有的观察者。
Subject : 观察源事物,可添加或删除自身观察者
Observer : 观察者,可接受事物的通知
当事物发生更新变动,则通知观察者做相应处理,另事物状态与观察者状态保持一致
目标与观察者之间的关系
(1)事物与观察者的关系,可以是一对多,也可能是多对多
(2)观察者依赖于目标事物,反向则不行
(3)事物类的命名应以Subject结尾,观察者对象则以Oberserver结尾
(4)为了让观察者与事物状态保持一致,应当在事物状态更新后再通知观察者
(5)事物通知多个观察者的顺序是平行的,没有先后之分
(6)执行流程:创建事物 -> 注册观察者 -> 更新事物 -> 通知观察者
实现的两种方式:推模型和拉模型
推模型:目标对象主动向观察者推送目标的详细信息推送的信息通常是目标对象的全部或部分数据(相当于广播通信)
拉模型:目标对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到目标对象中获取,相当于是观察者从目标对象中拉数据。(主动请求)
一般这种模型的实现中,会把目标对象自身通过 update 方法传递给观察者
两种模型比较:
推模型:假定目标对象知道观察者需要的数据(按需分配,复用性差 )
拉模型:目标对象不知道观察者具体需要什么数据,因此把自身传给观察者,由观察者来取值。复用性好。
拉模型下,update 方法的参数是目标对象本身,基本上可以适应各种情况的需要。
利用Java提供的观察者实现
JDK中提供了观察者模式实现的接口:
事物类可继承 java.util.Observable 类作为 被观察对象,此类对状态更新设置更精确,更安全
观察者类可实现 java.util.Observer 接口 作为观察者对象
Observable类对notifyObservers()方法进行了重载,即notifyObservers()与notifyObservers(Object arg).
前者用于拉模型,后者用于推模型。
目标类代码
/**
* 目标类,继承Observable类,使其成为 可观察的目标类
*/
public class WeatherSubject extends Observable{
private String weatherState;
public String getWeatherState(){
return weatherState;
}
public void setWeatherState(String weatherState){
this.weatherState = weatherState;
this.setChanged(); //通知之前必须要调用该方法,否则无法通知
this.notifyObservers("参数");//通知所有的观察者。不管这里传不传参数,都会传给观察者Observable引用。
}
}
观察者代码
/**
* 观察者类,实现Observer接口,成为观察者
*/
public class WeatherObserver implements Observer{
private String name;//随便定义一个变量,作为观察者的名字
public WeatherObserver(String name){
this.name=name;
}
/**
* Observer接口中的方法,Observable目标类会回调该方法
* @param observable 目标类的引用,需要进行强制类型转换 //不管通知传不传参数,都会传给观察者Observable引用。
* @param object 目标类主动传来的对象。 如果目标类的通知没传参数,则object为空
*/
@Override
public void update(Observable observable, Object object){
System.out.println(name+"收到通知,推送值为"+object+",天气为"+((WeatherSubject)observable).getWeatherState());
}
}
观察者优缺点?
优点:
1,观察者模式实现了观察者和目标之间的抽象耦合;
2,观察者模式实现了动态联动
3,观察者模式支持广播通信
缺点:
可能会引起无谓的操作---->引起误更新
何时使用观察者模式?(触发联动)
①当一个抽象模型有两个方面,其中一个方面的操作依赖于另外一个方面的状态的变化。
②如果更改一个对象的时候,需要同时连带更改其他对象,而且不知道究竟有多少对象要被连带改变。
③当一个对象必须通知其他对象,但是又不希望这个对象和其他被通知的对象是松散耦合的,也就是说这个对象不想知道具体被通知的对象;
以上三种情况可以考虑观察者模式。
区别对待的观察者模型
场景:
张三希望只接收下雨天的天气预报
李四希望只接收下雨/下雪天的天气预报。
需要根据不同的天气情况,区别对待通知不同的观察者
区别对待的观察者模型中和通用观察者模型的却别在于要根据不同的观察者来进行不同的推送,所以区别在于目标类中的统治方法需要在具体的目标类中进行实现。(因为需要根据不同的情况进行更新,所以需要在具体的目标类中实现刚刚那个方法)