首页 > 代码库 > 利用事件委托弥补观察者模式不足
利用事件委托弥补观察者模式不足
前两篇我们自己首先实现了一个观察者模式,我们再利用Java自带的接口和类实现了观察者模式,但其实两种观察者模式存在不足的地方。之前两种观察者模式的观察者(订阅者)都是实现了一个同一个接口,实现了接口中的update方法,但是如果两个观察者风马牛不相及,完全无关呢?或者他们的方法名不一样这个时候该怎么办呢?《大话设计模式》中C#提供了事件委托,但在Java中比没有提供。此时,我们可以利用Java的反射机制来实现事件委托从而来弥补观察者模式的不足。
我们先来看看客户端的测试代码,直观的感受一下和之前的观察者模式有什么不同。
1 package day_11_event; 2 3 import java.util.Date; 4 5 /** 6 * 利用事件委托 7 * @author turbo 8 * 9 * 2016年9月16日10 */11 public class Main {12 13 /**14 * @param args15 */16 public static void main(String[] args) {17 Notifier notifier = new ConcreteNotifier();18 Observer1 observer1 = new Observer1();19 Observer2 observer2 = new Observer2();20 21 notifier.attach(observer1, "changeState1", new Date());22 notifier.attach(observer2, "changeState2", new Date());23 24 notifier.notifyObj();25 }26 27 }
我们的观察者observer1、observer2是两个不相关的观察者,可以看到两者需要改变状态的方法分别是changeState1、changeState2,如果使用之前的观察者模式则是实现同一个接口实现同一个方法。如果遇到现在这种情况,则没办法了。
由于Java并没有为我们提供事件委托,我们首先需要自己实现一个事件类。
1 package day_11_event; 2 3 import java.lang.reflect.Method; 4 5 /** 6 * 事件类 7 * @author turbo 8 * 9 * 2016年9月16日10 */11 public class Event {12 private Object object;13 private String methodName;14 private Object[] params;15 private Class[] paramsType;16 17 public Event(Object object, String methodName, Object...args){18 this.object = object;19 this.methodName = methodName;20 this.params = args;21 contractParamTypes(this.params);22 }23 24 /**25 * @param params226 */27 private void contractParamTypes(Object[] params2) {28 this.paramsType = new Class[params2.length];29 for (int i = 0; i < params.length; i++){30 this.paramsType[i] = params[i].getClass();31 }32 }33 34 public void invoke() throws Exception{35 Method method = object.getClass().getMethod(this.methodName, this.paramsType);36 if (null == method){37 return ;38 }39 method.invoke(this.object, this.params);40 }41 }
利用反射实现一个事件类后,我们还需要实现一个管理事件的类。
1 package day_11_event; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 /** 7 * 管理事件类 8 * @author turbo 9 *10 * 2016年9月16日11 */12 public class EventHandler {13 private List<Event> objects;14 15 public EventHandler(){16 objects = new ArrayList<Event>();17 }18 19 public void addEvent(Object object, String methodName, Object...args){20 objects.add(new Event(object, methodName, args));21 }22 23 public void notifyObj() throws Exception{24 for (Event event : objects){25 event.invoke();26 }27 }28 }
这样我们就利用Java完成了我们事件委托的基本模型。
基本工作做好后,我们来实现观察者模式。
1 package day_11_event; 2 3 /** 4 * 抽象通知者 5 * @author turbo 6 * 7 * 2016年9月16日 8 */ 9 public abstract class Notifier {10 private EventHandler eventHandler = new EventHandler();11 12 public EventHandler getEventHandler() {13 return eventHandler;14 }15 16 public void setEventHandler(EventHandler eventHandler) {17 this.eventHandler = eventHandler;18 }19 20 public abstract void attach(Object object, String methodName, Object...args);21 22 public abstract void notifyObj();23 }
1 package day_11_event; 2 3 /** 4 * 具体通知者 5 * @author turbo 6 * 7 * 2016年9月16日 8 */ 9 public class ConcreteNotifier extends Notifier {10 11 /* (non-Javadoc)12 * @see day_11_event.Notifier#attach(java.lang.Object, java.lang.String, java.lang.Object[])13 */14 @Override15 public void attach(Object object, String methodName, Object... args) {16 this.getEventHandler().addEvent(object, methodName, args);17 }18 19 /* (non-Javadoc)20 * @see day_11_event.Notifier#notifyObj()21 */22 @Override23 public void notifyObj() {24 try {25 this.getEventHandler().notifyObj();26 } catch (Exception e) {27 e.printStackTrace();28 }29 }30 31 }
通知者我们同样还是定义了一个抽象类,并实现了一个具体的通知类。
下面是两个观察者,两个观察者没有任何关系,不必实现同一个接口。
1 package day_11_event; 2 3 import java.util.Date; 4 5 /** 6 * 观察者1 7 * @author turbo 8 * 9 * 2016年9月16日10 */11 public class Observer1 {12 public Observer1(){13 System.out.println("Observer1状态1");14 }15 16 public void changeState1(Date date){17 System.out.println("Observer1改变状态" + date);18 }19 }
1 package day_11_event; 2 3 import java.util.Date; 4 5 /** 6 * 观察者2 7 * @author turbo 8 * 9 * 2016年9月16日10 */11 public class Observer2 {12 public Observer2(){13 System.out.println("Obsever2状态1");14 }15 16 public void changeState2(Date date){17 System.out.println("Observer2改变状态" + date);18 }19 }
客户端在开头给出,这里我们不再给出。利用事件委托确实为我们解决了观察者完全不相关,但是又想他们俩都收到通知的难题。这得归功于Java的反射机制,在之前的抽象工厂模式中我们也利用了Java的反射机制。看似平时用得不多的反射,但是却能为我们做很多事情,Java并不是想象中的那么简单。
利用事件委托弥补观察者模式不足