观察者模式和发布/订阅模式
- 概念
- 观察者模式和发布/订阅模式区别
- 为什么要使用委托机制
- 观察者模式和委托机制类图
- 观察者模式和委托机制代码实例
概念
观察者模式是一种一对多的依赖关系,让多个观察者对象同时监听同个主题对象。当这个主题对象在状态发生变化时,会通知所有注册到主题对象的观察者对象,使他们能够自动更新自己。
观察者模式和发布/订阅模式区别
观察者模式:
比较概念的解释是,目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更新接口。具体观察者和具体目标继承各自的基类,然后具体观察者把自己注册到具体目标里,在具体目标发生变化时候,调度观察者的更新方法。
比如有个“天气中心”的具体目标A,专门监听天气变化,而有个显示天气的界面的观察者B,B就把自己注册到A里,当A触发天气变化,就调度B的更新方法,并带上自己的上下文
发布/订阅模式:
比较概念的解释是,订阅者把自己想订阅的事件注册到(调度中心),当该事件触发时候,发布者发布该事件到调度中心(顺带上下文),由调度中心统一调度订阅者注册到调度中心的处理代码。
比如有个界面是实时显示天气,它就订阅天气事件(注册到调度中心,包括处理程序),当天气变化时(定时获取数据),就作为发布者,发布天气信息到调度中心,调度中心就调度订阅者的天气处理程序。
总结:
从两张图片可以看到,最大的区别是调度的地方。
虽然两种模式都存在订阅者和发布者(具体观察者可认为是订阅者、具体目标可认为是发布者),但是观察者模式是由具体目标调度的,而发布/订阅模式是统一由调度中心调的,所以观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会
订阅者模式,有两种:
一种是以前的RSS Reeder的那种订阅者方法,用户对指定内容申请订阅,内容发布者记录下来,定期发送更新内容给订阅者。这种方式不需要一个调度中心的存在,由发布者采用分发方式分别发送给订阅者,可以一次性发送或者慢慢发。
第二种是现在的消息分发,如redis, ZeroMQ(消息队列)等,存在一个调度中心,由调度中心负责所有的订阅管理、分发管理,发布者只需要发送一次,其他的事情就交给调度中心来处理。
观察者模式,所说的相当于第一种订阅者模式
消息队列发布/订阅者模型:
为什么要使用委托机制
观察者模式不好之处就是:如果想因触发某个事件通知观察者,必须要实现抽象观察者接口,而若是第三方类库不能修改源码,则只能使用委托机制进行通知,还有就是实现抽象观察者对象接口都是同个方法,但是有时候可能为add、delete操作而不是仅仅update操作。 所以java通过反射实现的委托机制可以通知执行任何一个类的任何一个方法
观察者模式和委托机制类图
观察者模式和委托机制代码实例
观察者模式代码
Observer 抽象观察者接口
/**
* @author duanyimiao
* @create 2018-10-04 2:30 PM
* @description 抽象观察者
**/
public interface Observer {
void update(String state);
}
Subject 抽象主题类
/**
* @author duanyimiao
* @create 2018-10-04 2:15 PM
* @description 抽象主题类(通知者)
**/
public abstract class Subject {
protected String state;
//依赖抽象观察者,符合依赖倒置原则 具体依赖抽象,抽象不依赖具体
protected List<Observer> observerList = new ArrayList<>();
public abstract void addObserver(Observer observer);
public abstract void deleteObserver(Observer observer);
public abstract void notifyUpdate();
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
ConcreteSubject 具体主题实现类
/**
* @author duanyimiao
* @create 2018-10-04 2:36 PM
* @description
**/
public class ConcreteSubject extends Subject {
@Override
public void addObserver(Observer observer) {
observerList.add(observer);
}
@Override
public void deleteObserver(Observer observer) {
observerList.remove(observer);
}
@Override
public void notifyUpdate() {
for (Observer observer : observerList) {
observer.update(state);
}
}
}
ConcreteObserver1 具体观察者类
/**
* @author duanyimiao
* @create 2018-10-04 2:40 PM
* @description 具体抽象者
**/
public class ConcreteObserver1 implements Observer {
//依赖抽象主题类
private Subject subject;
public ConcreteObserver1(Subject subject) {
this.subject = subject;
}
@Override
public void update(String state) {
System.out.println("ConcreteObserver1 from subject = " + subject.getState());
}
}
ConcreteObserver2 具体观察者类
/**
* @author duanyimiao
* @create 2018-10-04 2:40 PM
* @description 具体抽象者
**/
public class ConcreteObserver2 implements Observer {
@Override
public void update(String state) {
System.out.println("ConcreteObserver2=" + state);
}
}
MainTest 测试类
/**
* @author duanyimiao
* @create 2018-10-04 2:42 PM
* @description
**/
public class MainTest {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
subject.setState("update");
ConcreteObserver1 concreteObserver1 = new ConcreteObserver1(subject);
ConcreteObserver2 concreteObserver2 = new ConcreteObserver2();
subject.addObserver(concreteObserver1);
subject.addObserver(concreteObserver2);
//主题对象状态改变了,将state状态通知给其他观察者
subject.notifyUpdate();
}
}
输出结果:
ConcreteObserver1 from subject = update
ConcreteObserver2=update
委托机制代码
Event 事件类,封装类某个对象的方法信息(方法名,参数值,参数类型)
/**
* @author duanyimiao
* @create 2018-10-04 4:08 PM
* @description 事件类
**/
public class Event {
//方法名
private String methodName;
//被委托类对象
private Object obj;
//被委托类中方法参数值
private Object[] params;
//被委托类中方法参数类型
private Class[] paramTypes;
public Event() {
}
public Event(String methodName, Object obj, Object ... params) {
this.methodName = methodName;
this.obj = obj;
this.params = params;
constructParams(params);
}
private void constructParams(Object[] params) {
paramTypes = new Class[params.length];
for (int i = 0;i<params.length;i++) {
paramTypes[i] = params[i].getClass();
}
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public Object[] getParams() {
return params;
}
public void setParams(Object[] params) {
this.params = params;
}
public Class[] getParamTypes() {
return paramTypes;
}
public void setParamTypes(Class[] paramTypes) {
this.paramTypes = paramTypes;
}
/**
* 通过反射机制根据方法名,参数值,参数类型,进而调用对象中方法来执行
*/
public void invoke(){
//通过obj对象获取类字节码对象,然后通过方法名和参数类型获取Method对象
try {
Method method = obj.getClass().getMethod(methodName,paramTypes);
if(method != null){
//通过Method对象进而执行
method.invoke(obj,params);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
EventHandler 事件处理器,封装类对Event对象相关的操作
/**
* @author duanyimiao
* @create 2018-10-04 4:10 PM
* @description 事件处理类
**/
public class EventHandler {
private List<Event> eventList = new ArrayList<>();
public void addEvent(String methodName, Object obj, Object ... params) {
eventList.add(new Event(methodName, obj, params));
}
public void eventNotify() {
for (Event event : eventList) {
event.invoke();
}
}
}
AbstractNotifier 抽象通知者
/**
* @author duanyimiao
* @create 2018-10-04 4:52 PM
* @description 抽象通知者相当于观察者模式的抽象主题类
**/
public abstract class AbstractNotifier {
private EventHandler eventHandler = new EventHandler();
public EventHandler getEventHandler() {
return eventHandler;
}
public void setEventHandler(EventHandler eventHandler) {
this.eventHandler = eventHandler;
}
public abstract void addListener(String methodName,Object obj,Object ... args);
public abstract void notifyAfterRun();
}
ConcreteNotifier 具体通知者
**
* @author duanyimiao
* @create 2018-10-04 4:59 PM
* @description 具体通知者
**/
public class ConcreteNotifier extends AbstractNotifier {
@Override
public void addListener(String methodName, Object obj, Object... args) {
getEventHandler().addEvent(methodName, obj, args);
}
@Override
public void notifyAfterRun() {
getEventHandler().eventNotify();
}
}
ToolBarListener 具体观察者
/**
* @author duanyimiao
* @create 2018-10-04 5:16 PM
* @description 工具栏监听器 具体的观察者类,不需要抽象观察者
**/
public class ToolBarListener {
public void openToolBar(String name){
System.out.println("open tool bar "+name);
}
}
DebuggerWindowListener 具体观察者
/**
* @author duanyimiao
* @create 2018-10-04 5:16 PM
* @description debug抽空监听器 具体的观察者类,不需要抽象观察者
**/
public class DebuggerWindowListener {
public void closeDebugger(String name,String state){
System.out.println("close debugger "+name+" state="+state);
}
}
MainTest 测试类
/**
* @author duanyimiao
* @create 2018-10-04 5:20 PM
* @description
**/
public class MainTest {
public static void main(String[] args) {
AbstractNotifier notifier = new ConcreteNotifier();
//如果toolBarListener和debuggerWindowListener都属于第三方类库中的类,那么无法让这些类实现抽象观察者接口,因此通过委托机制来实现,还有一个好处就是可以通知任意一个类中的任意一个方法
ToolBarListener toolBarListener = new ToolBarListener();
DebuggerWindowListener debuggerWindowListener = new DebuggerWindowListener();
notifier.addListener("openToolBar",toolBarListener,"notify open");
notifier.addListener("closeDebugger",debuggerWindowListener,"notify close","close");
//在点击运行按钮,触发上面注册的事件
notifier.notifyAfterRun();
}
}
输出结果
open tool bar notify open
close debugger notify close state=close