1

我有以下域对象:

public interface Event {}    
public class FirstEvent {}    
public class SecondEvent {}

然后我有另一个模块,它应该与我的域对象完全解耦,这意味着它知道域对象,但域对象不应该知道这个附加模块的存在。

在这个模块中,我通过通用接口接收对象Event,我需要根据特定的事件类型采取不同的行动。

目前我的代码如下所示:

if (event instanceof FirstEvent.class) {
    doFirst();
}
else if (event instanceof SecondEvent.class) {
    doSecond();
}

它工作得很好,但是静态分析工具和代码审查者抱怨我不应该使用instanceof它,我应该用更多的面向对象的方法来替换它。反射或getClass()也不是一种选择。

如何在 Java 中做到这一点?

我已经查看了许多关于替换的现有问题,instanceof但所有这些问题都建议将一些逻辑直接添加到域对象中。但是,在这种情况下,我不想用特定于我的模块的逻辑来污染它们。

4

2 回答 2

3

访客模式,又名双重调度,在这里通常很有用。

为每个已知事件类型定义一个接口,每个事件实现一个接口方法,该方法允许外部对象使用该接口的实现来调用它。然后,该事件确保使用其自己的“this”引用调用接口的特定类型方法,这样您就不会得到任何明确的向下转换。

public interface EventVisitor  {
    visit(FirstEvent firstEvent);
    visit(SecondEvent secondEvent);
}

public class FirstEvent {
    ...
    public void allowVisit(EventVisitor ev) {
        ev.visit(this); // calls the 'FirstEvent' overriden method
    }
    ...
}


public class SecondEvent {
    ...
    public void allowVisit(EventVisitor ev) {
        ev.visit(this); // calls the 'SecondEvent' overriden method
    }
    ... 
}

public class MyOtherObject implements EventVisitor, EventListener {
   ...
   public void signalEvent(Event e) {
       e.allowVisit(this);
   }

   public void visit(FirstEvent e) {
       // handle FirstEvent type
   }

   public void visit(SecondEvent e) {
       // handle SecondEvent type
   }

}

这种类型的缺点是添加新的事件类型变得很困难,因为您的 EventListener 接口必须枚举它们。你可以用一种包罗万象的方法“有点”解决这个问题,但它很混乱,而且仍然难以升级。

于 2016-04-06T16:47:01.520 回答
0

排除Reflection是可以理解的,但使用getClass()不应该是问题。

我处理这个问题的解决方案:

import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;

public class DynamicDispatch{
    Map<String,Event> events = new ConcurrentHashMap<String,Event>();
    public DynamicDispatch(){
        Event event = new FirstEvent();
        events.put(event.getName(),event);
        event = new SecondEvent();
        events.put(event.getName(),event);
    }
    public Event getEvent(String eventName){
        return events.get(eventName);
    }
    public static void main(String args[]){
        DynamicDispatch dispatchObj = new DynamicDispatch();
        Event event = dispatchObj.getEvent(args[0]);
        System.out.println("dispatchObj:"+event+":"+event.getName());
    }
}

interface Event {
    public String getName();
}
class FirstEvent implements Event{
    public String getName(){
        //return this.getClass().getSimpleName();
        return "FirstEvent";
    }
}
class SecondEvent implements Event{
    public String getName(){
        //return this.getClass().getSimpleName();
        return "SecondEvent";
    }
}

输出:

java DynamicDispatch FirstEvent
dispatchObj:FirstEvent@72d86c58:FirstEvent

java DynamicDispatch SecondEvent
dispatchObj:SecondEvent@72d86c58:SecondEvent

我仍然更喜欢使用return this.getClass().getSimpleName();而不是硬编码该值。

我希望上面的代码应该没问题static analysis tools

于 2016-04-06T18:36:51.093 回答