在 Java 中实现通用接口

发布于 2024-10-05 05:54:52 字数 711 浏览 0 评论 0原文

我有一个 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 接口以便实现最终结果?

I have a Java generics question I was hoping someone could answer. Consider the following code:

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

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

I want to implement this Handles interface like this:

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

But java doesn't allow implementing Handles twice using the Generic. I was able to accomplish this with C#, but cannot figure a workaround in java without using Reflection or instanceof and casting.

Is there a way in java to implement the Handles interface using both generic interfaces? Or perhaps another way to write the Handles interface so the end result can be accomplished?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

亢潮 2024-10-12 05:54:52

追随@Amir Raminfar,您可以使用 访客 模式

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){}
}

Going after @Amir Raminfar, you can use visitor pattern

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){}
}
萌酱 2024-10-12 05:54:52

在 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){}
}

You can't do that in Java. You can only implement one concrete realization of the same generic interface. I would do this instead:

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){}
}
忆依然 2024-10-12 05:54:52

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

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

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

No, because different "concrete" generic types in Java compile to the same type. The actual interface your object will implement is:

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

And, obviously, you can't have two different methods with an identical signature...

撩起发的微风 2024-10-12 05:54:52

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

与 C# 不同,Java 运行时期间不提供通用信息。这就是为什么它按照你所描述的方式工作。

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

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

AFAIK you cannot do that, because when compiling the source code in Java these will both boil down to handle(Event), making the method ambiguous.

The generic information is not available during runtime in Java, in contrast to C#. That is why there it works as you describe.

You will have to change the method names to make them unique, like handleAddressChanged and handleAddressDiscarded.

This is indeed one of the weak points of Java generics.

若沐 2024-10-12 05:54:52

不幸的是没有。通常的解决方案(胖、丑、快)是创建一个 Handles 接口(即 HandlesAddressChangeHandlesAddressDiscarded),并给每个接口一个不同的值。方法(handleAddressChange(...)handleAddressDiscarded())。

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

或者您可以使用匿名类。

Unfortunately not. The usual solution (fat, ugly, fast) is to create one Handles interface (i.e. HandlesAddressChange, HandlesAddressDiscarded) and give each of them a different method (handleAddressChange(...), handleAddressDiscarded()).

That way, the Java runtime can tell them apart.

Or you can use anonymous classes.

客…行舟 2024-10-12 05:54:52

这是不允许的,因为 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);
  }
}

It isn't allowed because Java erases generic signatures during compilation. The interface method will actually have the signature

public void handle(Object event);

So you have two choices. Either implement separate Handlers for different events:

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

or implement one handler for all but check the type of the incoming event:

public void handle(Event e){
  if (e instanceof AddressChanged) {
     handleAdressChanged(e);
  }
  else if (e instanceof AddressDiscareded) {
     handleAdressDiscarded(e);
  }
}
新雨望断虹 2024-10-12 05:54:52

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

首先,您必须创建注释。

@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){}
}

An implementation like this won't work due to the constraints of the java specification.
But if you're not afraid to use AOP or some sort of an IOC-Container you could use annotations for that. Than your Aspects or the container could manage the messaging infrastructure and call the methods you annotate.

First you have to create the annotations.

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

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

The you may annotate your class like that:

@EventConsumer
public class AddressHandler{
    @Handles
    public void handle(AddressChanged e){}
    @Handles
    public void handle(AddressDiscarded e){}
}
心不设防 2024-10-12 05:54:52

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

https:// github.com/bertilmuth/requirementsascode

您可以构建一个这样的模型

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

并运行它。

网站上描述了具体如何做到这一点。

If you don't mind using a (small) library, here's one I wrote that solves your problem:

https://github.com/bertilmuth/requirementsascode

You'd build a model like this

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

and run it.

How to do that exactly is described on the website.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文