【问题标题】:Observer design -- how to access method.invoke scope?观察者设计——如何访问 method.invoke 范围?
【发布时间】:2010-11-09 00:02:17
【问题描述】:

我目前有一个 Java Observer/Observable 设置,我在其中打开 Observer.update 的 Object 参数中的某些字段(例如事件 ID)以确定如何处理 Observable 通知。

这会创建像这样的详细代码:

public void update (Observable o, Object arg) {
    if (arg instanceof Event) {
        switch (((Event)arg).getID()) {
            case EVENT_TYPE_A:
                // do stuff...
                break;
            case EVENT_TYPE_B:
                // do stuff...
                break;
            case EVENT_TYPE_C:
                // do stuff...
                break;
        }
    }
}

来自 ActionScript 背景,这对我来说是不必要的冗长...与其传递 Observer 的实例,我更愿意传递一个回调方法以由 Observable 直接调用(更具体地说,由子类调用) )。但是,我不清楚如何确定应该调用该方法的对象(“拥有”该方法的类实例)。

我可以传递对包含该方法的实例的引用,但这听起来像糟糕的 OOP。

我是在叫错树吗?还是有一种干净的方法来实现这一点?

【问题讨论】:

标签: java events actionscript observer-pattern


【解决方案1】:

这在left-field 中可能有点远,但由于Java 5 及更高版本具有泛型,传统的观察者和侦听器模式似乎都有些过时了。也就是说,类型是当今 java 的 lingua-fraca。存在具有整数 ID 的事件主要是因为针对常量的 switch 语句非常有效 - 以牺牲可读性为代价,并且通常需要强制转换来做任何有用的事情(您可能知道如果 ID = 23,对象必须是 MouseEvent,但它更好如果您让编译器和运行时类型信息为您处理这个问题,则更安全)。在现代 JVM 中的现代机器上,效率可能不值得。

所以,如果你不习惯 ID 和传统的观察者模式,你可能会考虑这样的事情:

public abstract class Observer<T> {
  private final Class<T> type;

  protected Observer(Class<T> type) {
    this.type = type;
  }

  //implement this method;  if it returns false, the event (object) 
  //is "consumed" and no other observers should be called
  public abstract boolean onEvent(T instance);

  protected final boolean matches(Object obj) {
    return type.isInstance(obj);
  }

  Boolean maybeDispatch(Object o) {
    if (matches(o)) {
      return onEvent(type.cast(o));
    }
    return null;
  }
}

这让我们(字面上)成为一个通用的事件观察者;我们像这样打开传入对象的type

public class Bus {
  private final List<Observer<?>> observers = new ArrayList<Observer<?>>();

  public void registerObserver(Observer<?> observer) {
    observers.add(observer);
  }

  public <T> void onEvent(T t) {
    Boolean keepGoing;
    for (Observer<?> obs : observers) {
      keepGoing = obs.maybeDispatch(t);
      if (keepGoing != null && !keepGoing.booleanValue()) {
        break;
      }
    }
  }
}

生成的代码(略微)效率较低,但编写这样一个“观察者”的子类具有无限的可读性。它看起来不像传统的观察者模式,但在功能上是等价的。

如果你还需要一个额外的“事件”参数,你可以做类似的逻辑来参数化两种类型。

【讨论】:

  • hm,非常有趣...现在,我想坚持使用 Java 的 Observer,但这似乎是以后重新架构的一个很好的候选者。我仍然是一个 java 菜鸟(如果你没有猜到的话),泛型对我来说是新的,尽管我已经将它们与 Collections 框架一起使用。但我开始意识到它们带来的灵活性,同时仍然保持类型安全和编译时的优点......
【解决方案2】:

更简洁的实现将涉及将事件是否可以由观察者/可观察者处理的逻辑移除到实际的观察者/可观察者本身。似乎 ActionScript 给您留下了关于观察者模式的有趣想法。观察(无双关语):

public interface Observer{

  public void update( Event arg );
}

public class Event{

  public int ID;
}

public Button implements Observer{

  public void update ( Event arg ){

     switch (arg.ID){

       case 1:  //Buttonsy handle events of type 1
         //do something useful;
         break;
       default:
         System.out.println("Buttons don't handle events of ID: " + arg.ID);
         break;
     }
  }
}

public ProgressBar implements Observer{

  public void update ( Event arg ){

     switch (arg.ID){

       case 2: //ProgressBars handle events of type 2 and 3
         //do something useful;
         break;
       case 3:
         //do something else useful;
         break;
       default:
         System.out.println("Progress bars don't handle events of ID: " + arg.ID);
         break;
     }
  }
}


public class Subject{

 private ArrayList<Observer> allUIControls;

 public registerControl( Observer control ){

   allUIControls.add( control );
 }

 public void updateControls ( Event arg ) {

   foreach ( Observer control in allUIControls ){

     //pass the event to each UI control, and let the EVENT decide if it can understand the Event.ID
     //its not the job of Subject to decide if the Observer is fit to handle the event. THIS IS NOT THE OBSERVER pattern.
     control.update( arg );
   }
 }
}

【讨论】:

  • 是的,这就是我现在所处的位置。我可以接受观察者事件处理程序中的开关。它只是与 ActionScript 的范例有些不同;我看到了每个的优点和缺点。
猜你喜欢
  • 1970-01-01
  • 2011-11-25
  • 1970-01-01
  • 2010-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-25
  • 1970-01-01
相关资源
最近更新 更多