2010-04-18 66 views
1

我在所有处理由事件总线类触发的事件的观察者类中都有类似于此的代码。 正如您所看到的,有很多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()); 
    } 
} 
+1

这是一个干净的,面向对象的方式来做到这一点。其他方式将使用切换瀑布事件的参数..你为什么认为这不明确? – Jack 2010-04-18 15:44:24

+0

@Jack如果您希望稍后添加更多活动,那么这是一个维护噩梦:总会有一个您忘记检查的活动。 – jqno 2010-04-18 15:53:00

+0

如果你有很多事件,那么它将会成为维护噩梦,直到​​你不给事件祖先类中的常见行为,而不是将它们全部分开。实际上,当number_events> a_considerable_amount时,你将发誓在任何情况下:/ – Jack 2010-04-18 15:56:13

回答

6

您可以通过添加监听器依次在每个事件消除事件。例如考虑

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

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

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

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

这将工作,但它会以某种方式破坏封装,事件不应该尝试处理自己:) – Jack 2010-04-18 15:48:40

+0

@Jack取决于情况,我认为。如果你真的不喜欢它,你可以添加一个处理程序类的并行树并将事件委托给它。 – jqno 2010-04-18 15:55:03

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. 

} 

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

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 
    } 
} 
+0

这样做的缺点是,如果有很多特殊情况,最终会得到一个更复杂的原始代码变体。 – jqno 2010-04-18 15:56:45

+0

是的,你应该准确地选择这个东西的粒度..当然,我们不知道他需要多少事件或种类的事件来为他的案例提供完美的解决方案..实际上,在类似的情况下,我会结束只要我意识到规范需要不同的东西就可以重构整个事物。 – Jack 2010-04-18 16:03:28

0

提高,而不必为每个事件单独的方法对瑞安的回答,您可以使用泛型。然后你可以这样写:

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()的实现,作为读者的练习。

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()); 
} 
相关问题