• 利用事件委托弥补观察者模式不足


    前两篇我们自己首先实现了一个观察者模式,我们再利用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 args
    15      */
    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 params2
    26      */
    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     @Override
    15     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     @Override
    23     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并不是想象中的那么简单。

  • 相关阅读:
    乱···
    分析不足,明确目标
    与寂寞有染,与爱情无关
    桃花运?桃花劫?
    诺基亚N91——4G硬盘+200万像素!!!
    【转载】我们什么时候结婚
    纪念新生命诞生
    【转载】为一套房子你要奋斗多少年
    【转载】一定要讲给你爱的人听的20个小故事
    快乐不快乐
  • 原文地址:https://www.cnblogs.com/yulinfeng/p/5876600.html
Copyright © 2020-2023  润新知