1 观察者模式概述
观察者模式又叫做发布-订阅模式。
观察者模式定义了一对多的依赖关系,让多个观察者对象监听同一个主题。当主题状态发生变化的时候,就会通知所有观察者对象,使对象能够自动更新自己。
什么时候用到?
当一个对象的改变需要 同时改变其他对象的时候,且不知道有多少对象需要被改变的时候。
好处
将一个系统分割成一系列相互协作的类需要维护对象之间的一致性,且这些对象之间可能是紧密耦合的,给重用和维护带来不便。
观察者模式的作用就是解除耦合,让耦合的双方都依赖于抽象而不是具体,将双方封装在独立的对象中可以使他们各自独立地改变和复用。
2 观察者模式结构图
组成:
Subject类:抽象主题或抽象通知者,有多个观察者引用。可以增加或删除观察者。
Observer类:抽象观察者,监听主题发生变化的接口。
ConcreteSubject:具体主题。当自己发送变化时,通知到观察者;
ConcreteObserver:具体观察者。用来更新自己,通常会根据主题变化主动更新自己。
3 观察者模式 的实现
观察者模式 的实现有两种方式,推或拉。
推:拿发布订阅的例子来说,用户订阅一个新闻模块,推模式即众多新闻模块只要有变化就全部推送给用户;
拉:由用户主动去查看自己想要查看的内容。
本篇只实现推模式。
Java代码如下:
1)抽象主题-模拟头条新闻版块
public interface Subject {
//观察者注册主题
public void addObserver(Observer obs);
//观察者取消主题
public void removeObserver(Observer obs);
//通知所有观察者
public void notfyObservers();
}
2)抽象观察者-模拟用户
public interface Observer {
public void udate(int moduleId, String news);
}
3)具体主题—不同的新闻模块
/**
* 主题2:NBA新闻
* @author GenshenWang.nomico
*/
public class NBANewsSubject implements Subject{
private final int NEWS_ID = 2;
private final String NEWS_CONTENT = "NBA新闻:宇宙第一人LBJ本月将开启中国行,可惜我看不到。";
private List<Observer> list = new ArrayList<>();
@Override
public void addObserver(Observer observer) {
list.add(observer);
}
@Override
public void removeObserver(Observer observer) {
list.remove(observer);
}
@Override
public void notfyObservers() {
for(Observer observer : list){
observer.udate(NEWS_ID, NEWS_CONTENT);
}
}
}
/**
* 主题2:科技新闻
* @author GenshenWang.nomico
*/
public class PhoneNewsSubject implements Subject{
private final int NEWS_ID = 1;
private final String NEWS_CONTENT = "科技新闻:iPHONE 8将在本月12日举行发布会!请准备好你的肾!";
private List<Observer> list = new ArrayList<>();
@Override
public void addObserver(Observer observer) {
list.add(observer);
}
@Override
public void removeObserver(Observer observer) {
list.remove(observer);
}
@Override
public void notfyObservers() {
for(Observer observer : list){
observer.udate(NEWS_ID, NEWS_CONTENT);
}
}
}
4)具体观察者-具体用户
public class CustomerA implements Observer {
private final int customerId = 001;
@Override
public void udate(int moduleId, String news) {
System.out.println("吃瓜群众" + customerId + "您好,您关注的新闻版块--" +
(moduleId == 1 ? "科技": "NBA") +"--有新动态:");
System.out.println("》》》【" + news +"】");
}
}
public class CustomerB implements Observer {
private final int customerId = 002;
@Override
public void udate(int moduleId, String news) {
System.out.println("吃瓜群众" + customerId + "您好,您关注的新闻版块--" +
(moduleId == 1 ? "科技": "NBA") +"--有新动态:");
System.out.println("》》》【" + news +"】");
}
}
public class CustomerC implements Observer {
private final int customerId = 003;
@Override
public void udate(int moduleId, String news) {
System.out.println("吃瓜群众" + customerId + "您好,您关注的新闻版块--" +
(moduleId == 1 ? "科技": "NBA") +"--有新动态:");
System.out.println("》》》【" + news +"】");
}
}
5)测试:
public class Main {
public static void main(String[] args) {
//主题-新闻版块
Subject phoneSubject = new PhoneNewsSubject();
Subject nbaSubject = new NBANewsSubject();
//观察者-吃瓜群众
Observer o1 = new CustomerA();
Observer o2 = new CustomerB();
Observer o3 = new CustomerC();
phoneSubject.addObserver(o1);
phoneSubject.addObserver(o2);
nbaSubject.addObserver(o1);
nbaSubject.addObserver(o3);
phoneSubject.notfyObservers();
System.out.println();
nbaSubject.notfyObservers();
}
}
输出:
吃瓜群众1您好,您关注的新闻版块–科技–有新动态:
》》》【科技新闻:iPHONE 8将在本月12日举行发布会!请准备好你的肾!】
吃瓜群众2您好,您关注的新闻版块–科技–有新动态:
》》》【科技新闻:iPHONE 8将在本月12日举行发布会!请准备好你的肾!】吃瓜群众1您好,您关注的新闻版块–NBA–有新动态:
》》》【NBA新闻:宇宙第一人LBJ本月将开启中国行,可惜我看不到。】
吃瓜群众3您好,您关注的新闻版块–NBA–有新动态:
》》》【NBA新闻:宇宙第一人LBJ本月将开启中国行,可惜我看不到。】
4 Tomcat中观察者模式的实现
Tomcat中控制组件生命周期的 Lifecycle,对Servlet实例的创建,Session的管理和Container等都使用到了观察者模式。
Lifecycle的观察者模式结构图如下:
如图:
LifecycleListener 即为抽象观察者,定义了一个lifecycleEvent方法。
ServerLifecycleListener 为具体观察者。
Lifecycle即为抽象主题,定义了管理观察者的方法和其他方法。
StandardServer代表具体主题。
LifecycleEvent:生命周期事件,对主题与发生的事件进行封装。
LifecycleSupport:生命周期管理的实用类,提供对观察者的添加,删除及通知观察者的方法。
Lifecycle在整个Tomcat中的作用:
(图片来源:http://blog.csdn.net/javaofeclipse/article/details/53957481)
在Tomcat中组件的生命周期是通过Lifecycle接口来控制的,组件只要继承这个接口并实现其中的方法就可以同统一被拥有它的组件控制了,这样一层一层控制直到最高级的组件Server。
当调用Satrtup开启Server后,主题就会通知观察者,就会一层一层通知Service下面的组件,逐一开启。
public void start() throws LifecycleException{
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
synchronized(services){
for(int i = 0; i < services.length; i++){
if(services[i] instanceof Lifecycle)
((Lifecycle)services[i]).start();
}
}
public void start() throws LifecycleException{
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
synchronized(services){
for(int i = 0; i < services.length; i++){
if(services[i] instanceof Lifecycle)
((Lifecycle)services[i]).start();
}
}
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}.fireLifecycleEvent(AFTER_START_EVENT, null);
}
参考:
(1)http://blog.csdn.net/javaofeclipse/article/details/53957481
(2)《深入分析Java Web》