一:场景说明
记得上初中时,网络还没有现在这么普及,校门口有个小卖部,我常常到哪里订阅报纸,来关心下“天下大事”(当然不止我一个人订阅啦)
如图订阅报纸流程:
订阅报纸的时候常常遇到几个问题?什么时候出版?出版内容是什么?延迟出版怎么办?谁通知我报纸到了?要我去取报纸?还是会有人送过来?等等
把这样的场景带到我们编程世界里来,我们的解决方案之一就是使用观察者设计模式。
二:观察者模式(Observer),定义对象间的一种一对多的依赖关系。当一个对象的状态或内容发生改变时,所有依赖它的对象都得到通知并被自动更新.
观察者模式的结构说明:
三:代码示例:
其实JDK已经实现的Subject和Observer接口的,我们直接可以使用,下面我会介绍的,这里还是先自己实现下,体会下吧
/**
* 观察者接口
* 提供通知更新方法 (可以在这个方法中回调目标对象)
* Created by Administrator on 2016/4/22.
*/
public interface Observer {
void update(Subject subject);
}
package com.dy.observer;
import java.util.ArrayList;
import java.util.List;
/**
* 目标对象 ,作为被观察者
* 它知道观察者,并提供注册和删除观察者
* Created by Administrator on 2016/4/22.
*/
public class Subject {
private List<Observer> observerList = new ArrayList<>();
/**
* 注册观察者 ,报纸订阅者
* @param observer
*/
public void attach(Observer observer){
observerList.add(observer);
}
/**
* 删除观察者
* @param observer
*/
public void detach(Observer observer){
observerList.remove(observer);
}
/**
* 通知所有观察者
* 每当报纸被印出来,及时主动通知所有订阅者,好让他们知道
*/
protected void notifyObserver(){
for (Observer observer:observerList){
observer.update(this);
}
}
}
package com.dy.observer;
/**
* 目标对象的继承者
* 负责具体观察者状态
* 当自己状态变化,通知所有观察者
* Created by Administrator on 2016/4/22.
*/
public class NewsPaper extends Subject {
private String subjectStatus;
/**
* 报纸内容
*/
private String content;
public String getSubjectStatus() {
return subjectStatus;
}
public void setSubjectStatus(String subjectStatus) {
this.subjectStatus = subjectStatus;
//状态改变,通知所有观察者
this.notifyObserver();
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
//内容有了,说明报纸被印刷出来了,通知所有观察者
this.notifyObserver();
}
}
package com.dy.observer;
/**
* 读者,报纸订阅者
*
* 观察者实现类
* 实现更新方法,使自身状态和目标状态保持一致
* Created by Administrator on 2016/4/22.
*/
public class Reader implements Observer {
private String observerStatus;
private String name;
public Reader(String name) {
this.name = name;
}
@Override
public void update(Subject subject) {
//实现更新方法,使自身状态和目标状态保持一致
//采用拉的方式
observerStatus = ((NewsPaper) subject).getSubjectStatus();
System.out.println(name+"收到了报纸,阅读它,内容是:"+((NewsPaper) subject).getContent());
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.dy.observer;
/**
* Created by Administrator on 2016/4/22.
*/
public class Client {
public static void main(String[] args) {
//报纸被观察者
NewsPaper newsPager = new NewsPaper();
//报纸订阅者,也就是观察者
Reader reader = new Reader("张三");
Reader reader1 = new Reader("李四");
Reader reader2 = new Reader("王二");
//注册订阅者
newsPager.attach(reader);
newsPager.attach(reader1);
newsPager.attach(reader2);
//印刷出报纸内容
newsPager.setContent("本期内容介绍观察者模式");
}
}
张三收到了报纸,阅读它,内容是:本期内容介绍观察者模式
李四收到了报纸,阅读它,内容是:本期内容介绍观察者模式
王二收到了报纸,阅读它,内容是:本期内容介绍观察者模式
Process finished with exit code 0
四:使用jdk实现观察者模式
注意修改对应代码
package com.dy.observer.java;
import java.util.Observable;
/**
* Created by Administrator on 2016/4/22.
*/
public class NewsPaper extends Observable {
/**
* 报纸内容
*/
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
//内容有了,说明报纸被印刷出来了,通知所有观察者
//注意JDK的observer模式的时候,下面这句代码不可少
this.setChanged();
//主动通知,这里用推的方式
this.notifyObservers(this.content);
//如果用的拉的方式,如下代码示例
//this.notifyObservers();
}
}
package com.dy.observer.java;
import java.util.Observable;
import java.util.Observer;
/**
* 读者,报纸订阅者
*
* 观察者实现类
* 实现更新方法,使自身状态和目标状态保持一致
* Created by Administrator on 2016/4/22.
*/
public class Reader implements Observer {
private String name;
public Reader(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object obj) {
System.out.println(name+"收到了报纸,目标推过来的内容是:"+obj);
//拉的方式你自己想想就知道了((NewsPaper) obj).getContent())
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Client {
public static void main(String[] args) {
//报纸被观察者
NewsPaper jdk_subject = new NewsPaper();
//报纸订阅者,也就是观察者
Reader reader = new Reader("张三");
Reader reader1 = new Reader("李四");
Reader reader2 = new Reader("王二");
//注册订阅者
jdk_subject.addObserver(reader);
jdk_subject.addObserver(reader1);
jdk_subject.addObserver(reader2);
//印刷出报纸内容
jdk_subject.setContent("本期内容介绍java JDK实现观察者模式");
}
}
王二收到了报纸,目标推过来的内容是:本期内容介绍java JDK实现观察者模式
李四收到了报纸,目标推过来的内容是:本期内容介绍java JDK实现观察者模式
张三收到了报纸,目标推过来的内容是:本期内容介绍java JDK实现观察者模式
Process finished with exit code 0