代码之家  ›  专栏  ›  技术社区  ›  nkr1pt

干净地处理事件

  •  1
  • nkr1pt  · 技术社区  · 16 年前

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

    @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 回复  |  直到 16 年前
        1
  •  6
  •   Ryan    16 年前

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

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

    您还可以考虑将完成/失败合并为单个事件,因为看起来您已经有了一个完成的方法。你可以处理完完整的事件并检查是否成功。如果成功,您可以开始提取,否则您可以设置失败状态。

    我的另一个想法是,为什么要设置一个新对象作为状态指示器。使用常量/枚举值可以更好地服务于此吗?

        2
  •  1
  •   jqno    16 年前

    是的,假设你控制了 Event 类和/或其子类。你可以加个摘要 handle 你的方法 事件 类,并将每个子类的特定代码移到该方法中。

    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();
    }
    
        3
  •  1
  •   Behrang Saeedzadeh    16 年前

    @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.
    
    }
    

        4
  •  0
  •   Jack    16 年前

    如果你需要做的只是实例化“状态”,比如 BusyDownloadedState 或 FinishedDownloadedState 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
      }
    }
    
        5
  •  0
  •   Dustin    16 年前

    改进了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()的实现留给读者作为练习。

        6
  •  0
  •   Skip Head    16 年前

    怎么样:

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