观察者设计——如何访问method.invoke作用域?

发布于 2024-10-02 01:45:28 字数 761 浏览 2 评论 0原文

我目前有一个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 背景,这对我来说感觉不必要的冗长...我宁愿传递一个由 Observable 直接调用的回调方法,而不是传递一个观察者的实例(更具体地说,由子类)。但是,我不清楚如何确定应调用该方法的对象(“拥有”该方法的类实例)。

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

我是不是找错树了?或者有没有一种干净的方法来实现这一目标?

i currently have a Java Observer/Observable setup in which i switch on some field within the Object parameter of Observer.update (e.g. event id) to determine how to handle an Observable notification.

this creates verbose code like:

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;
        }
    }
}

coming from an ActionScript background, this feels unnecessarily verbose to me...instead of passing an instance of an Observer, i'd prefer to pass a callback method to be called directly by the Observable (more specifically, by a subclass). however, i'm not clear how to determine the object on which the method should be invoked (the class instance that 'owns' the method).

i could pass a reference to the instance enclosing the method, but this smells like bad OOP.

am i barking up the wrong tree? or is there a clean way to achieve this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

愿与i 2024-10-09 01:45:28

这可能有点离谱,但由于 Java 5 及更高版本有泛型,传统的观察者和侦听器模式似乎都有点过时了。也就是说,类型是当今 Java 的常用语言。具有整数 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;
  }
}

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

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;
      }
    }
  }
}

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

如果您仍然需要额外的“事件”参数,您可以执行类似的逻辑来对两种类型进行参数化。

This may be a little far out in left-field, but since Java 5 and up have generics, both the traditional observer and listener patterns seem a little bit dated. That is to say, types are the lingua-fraca of java these days. Events with integer IDs exist principally because switch statements against constants are extremely efficient - at the expense of readability and often requiring casts to do anything useful (you may know that if the ID = 23, the Object must be a MouseEvent, but it is nicer and safer if you let the compiler and runtime type information take care of this for you). On a modern machine in a modern JVM, the efficiency may not be worth it.

So, if you are not married to IDs and the traditional observer pattern, you might consider something like this:

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;
  }
}

This gets us (literally) a generic Observer of events; we switch on the type of the object passed in like this:

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;
      }
    }
  }
}

The resulting code is (marginally) less efficient, but writing a subclass of such an "observer" is infinitely more readable. It does not look much like the traditional observer pattern, but is functionally equivalent.

If you still need an additional "event" parameter, you can just do similar logic to parameterize on two types.

伴梦长久 2024-10-09 01:45:28

更清晰的实现将涉及将事件是否可以由观察者/可观察对象处理的逻辑删除到实际观察者/可观察对象本身。看起来 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 );
   }
 }
}

A cleaner implementation would involve removing the logic of whether the event can be handled by the observer/observable, to the actual observer/observable itself. It appears as if ActionScript has left you with a funny idea about the Observer pattern. Observe (no-pun-intended):

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 );
   }
 }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文