干净地处理事件

时间:2010-04-18 15:39:48

标签: java events

我在处理事件总线类触发的事件的所有观察者类中都有与此类似的代码。 正如您所看到的,有很多实例检查可以选择适当处理事件所需的操作路径,我想知道这是否可以更干净地完成,从而消除了实例测试?

@Override
public void handleEvent(Event event) {
    if (event instanceof DownloadStartedEvent) {
        DownloadStartedEvent dsEvent = (DownloadStartedEvent)event;
        dsEvent.getDownloadCandidateItem().setState(new BusyDownloadingState());
    } else if (event instanceof DownloadCompletedEvent) {
        DownloadCompletedEvent dcEvent = (DownloadCompletedEvent)event;
        dcEvent.getDownloadCandidateItem().setState(new FinishedDownloadingState());
        DownloadCandidate downloadCandidate = dcEvent.getDownloadCandidateItem(). getDownloadCandidate();
        if (downloadCandidate.isComplete()) {
            // start extracting
        }
    } else if (event instanceof DownloadFailedEvent) {
        DownloadFailedEvent dfEvent = (DownloadFailedEvent)event;
        dfEvent.getDownloadCandidateItem().setState(new FailedDownloadingState());
    }
}

6 个答案:

答案 0 :(得分:6)

您可以依次为每个事件添加侦听器来消除事件。例如,考虑

public void handleStartedEvent(DownloadStartedEvent ev) { ... }
public void handleCompletedEvent(DownloadCompletedEvent ev) { ... }
public void handleFailedEvent(DownloadFailedEvent ev) { ... }

您也可以考虑将Completed / Failed组合到单个事件中,因为看起来您已经有了isCompleted方法。您可以处理CompleteEvent并检查是否成功。如果成功,您可以开始提取,否则您可以设置失败状态。

我的另一个想法是你为什么要将一个新对象设置为状态指示器。使用常量/枚举值可能更好吗?

答案 1 :(得分:1)

是的,假设您控制Event类和/或其子类。您可以向handle类添加抽象Event方法,并将每个子类的特定代码移动到该方法中。

看起来像这样:

abstract class Event {
  //...
  public abstract void handle();
}

class DownloadStartedEvent extends Event {
  //...
  @Override
  public void handle() {
    getDownloadCandidateItem().setState(new BusyDownloadingState());
  }
}

// The same for the other classes

在您的通话代码中,您只需写下:

@Override
public void handleEvent(Event event) {
  event.handle();
}

答案 2 :(得分:1)

您可以使用注释提出更清晰的解决方案。您需要定义@EventHandler@HandlesEvent,然后使用它:

@EventHandler
public class MyEventHandler {

   @HandlesEvent(DownloadStartedEvent.class)
   public void handleDownloadStartedEvent(DownloadStartedEvent dse) {
      dsEvent.getDownloadCandidateItem().setState(new BusyDownloadingState());
   }

   @HandlesEvent(DownloadCompletedEvent.class)
   public void handleDownloadCompletedEvent(DownloadComletedEvent dse) {
      dcEvent.getDownloadCandidateItem().setState(new FinishedDownloadingState());
      DownloadCandidate downloadCandidate = dcEvent.getDownloadCandidateItem(). getDownloadCandidate();
      if (downloadCandidate.isComplete()) {
            // start extracting
      }
   }


   // etc.

}

当然,你需要额外的代码来注册这个类,它需要使用反射来检查哪个方法处理哪个事件。然后,您的observable与此注册器进行交互,后者又与上述@EventHandler注释类进行交互。

答案 3 :(得分:0)

如果您需要做的只是实例化“状态”,例如BusyDownloadedStateFinishedDownloadedState,您可以为您的Event类提供一个属性,说明哪个是必须设置的状态根据事件的类型。

如果你需要同时拥有简单的事件和复杂的事件,你可以混合使用两件事:

class Event
{
   State state;
   boolean isSimple;
}

public void handleEvent(Event event)
{
  if (event.isSimple)
    setState(event.state)
  else
  {
     if (event instanceof WhateverEvent)
        // special handling
  }
}

答案 4 :(得分:0)

改进Ryan的答案,而不是为每个事件使用单独的方法,您可以使用泛型。然后你可以写:

public void registerListeners() {

eventSource.addListener(DownloadStartedEvent.class, new EventHandler<DownloadStartedEvent>() {
    public void handleEvent(DownloadStartedEvent event) {
        dsEvent.getDownloadCandidateItem().setState(new BusyDownloadingState());
    }
});

eventSource.addListener(DownloadCompletedEvent.class, new EventHandler<DownloadCompletedEvent>() {
    public void handleEvent(DownloadCompletedEvent event) {
        dcEvent.getDownloadCandidateItem().setState(new FinishedDownloadingState());
        DownloadCandidate downloadCandidate = dcEvent.getDownloadCandidateItem(). getDownloadCandidate();
        if (downloadCandidate.isComplete()) {
            // start extracting
        }
    }
});

eventSource.addListener(DownloadFailedEvent.class, new EventHandler<DownloadFailedEvent>() {
    public void handleEvent(DownloadFailedEvent event) {
        dfEvent.getDownloadCandidateItem().setState(new FailedDownloadingState());
    }
});
}

我将addListener()的实现作为读者的练习。

答案 5 :(得分:0)

怎么样:

public void handleEvent(Event e) {
   // Not interested
}


public void handleEvent(DownloadStartedEvent dsEvent) {
    dsEvent.getDownloadCandidateItem().setState(new BusyDownloadingState());
}


public void handleEvent(DownloadCompletedEvent dcEvent) {
    dcEvent.getDownloadCandidateItem().setState(new FinishedDownloadingState());
    DownloadCandidate downloadCandidate = dcEvent.getDownloadCandidateItem().getDownloadCandidate();
    if (downloadCandidate.isComplete()) {
        // start extracting
    }
}

public void handleEvent(DownloadFailedEvent dfEvent) {
    dfEvent.getDownloadCandidateItem().setState(new FailedDownloadingState());
}