在Java中实现通用接口

时间:2010-12-01 15:36:48

标签: java generics cqrs

我有一个Java泛型问题我希望有人可以回答。请考虑以下代码:

public interface Event{}
public class AddressChanged implements Event{}
public class AddressDiscarded implements Event{}

public interface Handles<T extends Event>{
    public void handle(T event);
}

我想像这样实现这个Handles接口:

public class AddressHandler implements Handles<AddressChanged>, Handles<AddressDiscarded>{
    public void handle(AddressChanged e){}
    public void handle(AddressDiscarded e){}
}

但java不允许使用Generic两次实现Handles。我能够使用C#完成此任务,但是如果不使用Reflection或instanceof并进行转换,则无法在java中找到解决方法。

java中有没有办法使用两个通用接口实现Handles接口?或者也许是另一种编写Handles接口的方法,以便完成最终结果?

8 个答案:

答案 0 :(得分:18)

在@Amir Raminfar之后,您可以使用visitor 模式

interface Event{
 void accept(Visitor v);
}
interface Visitor {
 void visitAddressChanged(AddressChanged a);
 void visitAddressDiscarded(AddressDiscarded a);
}

class AddressChanged implements Event{
 @Override
 public void accept(Visitor v) {
  v.visitAddressChanged(this);
 } 
}

class AddressDiscarded implements Event{
 @Override
 public void accept(Visitor v) {
  v.visitAddressDiscarded(this);
 } 
}

class AddressHandler implements Visitor {
    void handle(Event e){
       e.accept(this);
     }
    public void visitAddressChanged(AddressChanged e){}
    public void visitAddressDiscarded(AddressDiscarded e){}
}

答案 1 :(得分:10)

你不能用Java做到这一点。您只能实现相同通用接口的一个具体实现。我会这样做:

public class AddressHandler implements Handles<Event>{
    public void handle(Event e){
      if(e instanceof AddressDiscarded){
         handleDiscarded(e);
      } else if(e instanceof AddressChanged){
         handleChanged(e);
      }
    }
    public void handleDiscarded(AddressDiscarded e){}
    public void handleChanged(AddressChanged e){}
}

答案 2 :(得分:2)

不,因为Java中不同的“具体”泛型类型编译为相同的类型。您的对象将实现的实际接口是:

public interface Handles {
    public void handle(Event event);
}

而且,显然,你不能有两种不同的方法具有相同的签名......

答案 3 :(得分:1)

AFAIK你不能那样做,因为在用Java编译源代码时,这些都会归结为handle(Event),使方法不明确。

与C#相比,Java中的运行时期间无法使用通用信息。这就是为什么它如你所描述的那样有效。

您必须更改方法名称才能使其唯一,例如handleAddressChangedhandleAddressDiscarded

这确实是Java泛型的弱点之一。

答案 4 :(得分:0)

不幸的是没有。通常的解决方案(胖,丑,快)是创建一个Handles接口(即HandlesAddressChangeHandlesAddressDiscarded)并为每个接口提供不同的方法(handleAddressChange(...),{ {1}})。

这样,Java运行时可以区分它们。

或者您可以使用匿名类。

答案 5 :(得分:0)

不允许这样做,因为Java在编译期间删除了通用签名。接口方法实际上会有签名

public void handle(Object event);

所以你有两个选择。为不同的事件实现单独的处理程序:

public class AddressChangedHandler implements Handles<AddressChanged>{ /* ... */ }
public class AddressDiscardedHandler implements Handles<AddressDiscarded>{ /* ... */ }

或为所有人实现一个处理程序,但检查传入事件的类型:

public void handle(Event e){
  if (e instanceof AddressChanged) {
     handleAdressChanged(e);
  }
  else if (e instanceof AddressDiscareded) {
     handleAdressDiscarded(e);
  }
}

答案 6 :(得分:0)

由于java规范的限制,这样的实现不起作用。 但是,如果您不害怕使用AOP或某种IOC-Container,您可以使用注释。比您的方面或容器可以管理消息传递基础结构并调用您注释的方法。

首先,您必须创建注释。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventConsumer {}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Handles{}

你可以这样注释你的课程:

@EventConsumer
public class AddressHandler{
    @Handles
    public void handle(AddressChanged e){}
    @Handles
    public void handle(AddressDiscarded e){}
}

答案 7 :(得分:0)

如果您不介意使用(小型)库,这里是我写的可以解决您问题的库:

https://github.com/bertilmuth/requirementsascode

你会构建一个这样的模型

Model.builder()
  .on(AddressChanged.class).system(this::handleAddressChanged)
  .on(AddressDiscarded.class).system(this::handleAddressDiscarded)
  .build()

并运行它。

网站上详细描述了如何做到这一点。