Java 通用接口

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1623480/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 17:55:33  来源:igfitidea点击:

Generic Interface

javainterface

提问by user192585

Let's say I wanted to define an interface which represents a call to a remote service. Now, the call to the remote service generally returns something, but might also include input parameters. Suppose that an implementing class will typically only implement one service method. Given the above information, is the following a poor design (it doesn't quite feel right):

假设我想定义一个接口来表示对远程服务的调用。现在,对远程服务的调用通常会返回一些东西,但也可能包括输入参数。假设一个实现类通常只实现一个服务方法。鉴于上述信息,以下是一个糟糕的设计(感觉不太对):

public interface IExecutesService<A,B>
{
    public A executeService();
    public A executeService(B inputParameter);
}

Now, let's say that I implement this interface with a class that executes a remote service with an input parameter:

现在,假设我使用一个类来实现此接口,该类使用输入参数执行远程服务:

public class ServiceA implements IExecutesService<String,String>
{
  public String executeService()
  {
    //This service call should not be executed by this class
    throw new IllegalStateException("This method should not be called for this class...blabla");
  }

  public String executeService(String inputParameter)
  {
    //execute some service
  }

I have two questions regarding the above:

关于上述问题,我有两个问题:

  1. Is the use of a generic interface (IExecutesService<A,B>) good in the case where you want to provide subclasses which require different input parameters and return types for the interface methods?
  2. How can I do the above better? I.e. I want to group my service executors under a common interface (IExecutesService); however, an implementing class will typically only implement one of the methods, and the use of an IllegalStateException feels really ugly. Also, the B type parameter in IExecutesService<A,B>will be redundant for an implementing class that calls a service without any input parameters. It also seems overkill creating two separate interfaces for the two different service calls.
  1. IExecutesService<A,B>在您想提供需要不同输入参数和接口方法返回类型的子类的情况下,使用泛型接口 ( ) 是否合适?
  2. 我怎样才能更好地做到以上几点?即我想将我的服务执行程序分组在一个通用接口 ( IExecutesService) 下;然而,一个实现类通常只会实现其中一种方法,并且使用 IllegalStateException 感觉非常难看。此外,对于在IExecutesService<A,B>没有任何输入参数的情况下调用服务的实现类,B 类型参数 in将是多余的。为两个不同的服务调用创建两个单独的接口似乎也有些矫枉过正。

采纳答案by cletus

Here's one suggestion:

这是一个建议:

public interface Service<T,U> {
    T executeService(U... args);
}

public class MyService implements Service<String, Integer> {
    @Override
    public String executeService(Integer... args) {
        // do stuff
        return null;
    }
}

Because of type erasure any class will only be able to implement one of these. This eliminates the redundant method at least.

由于类型擦除,任何类都只能实现其中之一。这至少消除了冗余方法。

It's not an unreasonable interface that you're proposing but I'm not 100% sure of what value it adds either. You might just want to use the standard Callableinterface. It doesn't support arguments but that part of the interface has the least value (imho).

您提议的界面并不是不合理的,但我也不能 100% 确定它会增加什么价值。您可能只想使用标准Callable接口。它不支持参数,但接口的那部分具有最小值(恕我直言)。

回答by Lucero

If I understand correctly, you want to have one class implement multiple of those interfaces with different input/output parameters? This will not work in Java, because the generics are implemented via erasure.

如果我理解正确,您想让一个类实现多个具有不同输入/输出参数的接口吗?这在 Java 中不起作用,因为泛型是通过擦除实现的。

The problem with the Java generics is that the generics are in fact nothing but compiler magic. At runtime, the classes do not keep any information about the types used for generic stuff (class type parameters, method type parameters, interface type parameters). Therefore, even though you could have overloads of specific methods, you cannot bind those to multiple interface implementations which differ in their generic type parameters only.

Java泛型的问题在于泛型实际上只是编译器魔术。在运行时,类不会保留有关用于泛型内容的类型(类类型参数、方法类型参数、接口类型参数)的任何信息。因此,即使您可以重载特定方法,也不能将它们绑定到仅在泛型类型参数上不同的多个接口实现。

In general, I can see why you think that this code has a smell. However, in order to provide you with a better solution, it would be necessary to know a little more about your requirements. Why do you want to use a generic interface in the first place?

总的来说,我能理解你为什么认为这段代码有味道。但是,为了向您提供更好的解决方案,有必要更多地了解您的要求。为什么首先要使用通用接口?

回答by dfa

Here's another suggestion:

这是另一个建议:

public interface Service<T> {
   T execute();
}

using this simple interface you can pass arguments via constructorin the concrete service classes:

使用这个简单的接口,您可以通过具体服务类中的构造函数传递参数

public class FooService implements Service<String> {

    private final String input1;
    private final int input2;

    public FooService(String input1, int input2) {
       this.input1 = input1;
       this.input2 = input2;
    }

    @Override
    public String execute() {
        return String.format("'%s%d'", input1, input2);
    }
}

回答by denis.zhdanov

I'd stay with two different interfaces.

我会留下两个不同的界面。

You said that 'I want to group my service executors under a common interface... It also seems overkill creating two separate interfaces for the two different service calls... A class will only implement one of these interfaces'

你说'我想将我的服务执行程序分组在一个公共接口下......为两个不同的服务调用创建两个单独的接口似乎也有点过分......一个类只会实现这些接口中的一个'

It's not clear what is the reason to have a single interface then. If you want to use it as a marker, you can just exploit annotations instead.

目前尚不清楚有一个单一界面的原因是什么。如果您想将其用作标记,则可以改为利用注释。

Another point is that there is a possible case that your requirements change and method(s) with another signature appears at the interface. Of course it's possible to use Adapter pattern then but it would be rather strange to see that particular class implements interface with, say, three methods where two of them trow UnsupportedOperationException. It's possible that the forth method appears etc.

另一点是,您的需求可能会发生变化,并且带有另一个签名的方法可能会出现在界面上。当然,那时可以使用适配器模式,但是看到特定类使用三个方法实现接口会很奇怪,其中两个方法会引发 UnsupportedOperationException。有可能出现第四种方法等。

回答by KLE

As an answer strictly in line with your question, I support cleytus's proposal.

作为与您的问题完全一致的答案,我支持克莱特斯的提议。



You could also use a marker interface (with no method), say DistantCall, with several several sub-interfaces that have the precise signatures you want.

您还可以使用标记接口(没有方法),例如DistantCall,带有几个具有您想要的精确签名的子接口。

  • The general interface would serve to mark all of them, in case you want to write some generic code for all of them.
  • The number of specific interfaces can be reduced by using cleytus's generic signature.
  • 通用接口将用于标记所有这些,以防您想为所有这些编写一些通用代码。
  • 通过使用 cleytus 的通用签名,可以减少特定接口的数量。

Examples of 'reusable' interfaces:

“可重用”接口的示例:

    public interface DistantCall {
    }

    public interface TUDistantCall<T,U> extends DistantCall {
      T execute(U... us);
    }

    public interface UDistantCall<U> extends DistantCall {
      void execute(U... us);
    }

    public interface TDistantCall<T> extends DistantCall {
      T execute();
    }

    public interface TUVDistantCall<T, U, V> extends DistantCall {
      T execute(U u, V... vs);
    }
    ....


UPDATEDin response to OP comment

更新以回应 OP 评论

I wasn't thinking of any instanceofin the calling. I was thinking your calling code knew what it was calling, and you just needed to assemble several distant call in a common interface for some generic code (for example, auditing all distant calls, for performance reasons). In your question, I have seen no mention that the calling code is generic :-(

我没有想到调用中的任何实例。我在想你的调用代码知道它在调用什么,你只需要在一个通用接口中为一些通用代码组装几个远程调用(例如,出于性能原因审计所有远程调用)。在你的问题中,我没有看到调用代码是通用的:-(

If so, I suggest you have only one interface, only one signature. Having several would only bring more complexity, for nothing.

如果是这样,我建议你只有一个界面,只有一个签名。有几个只会带来更多的复杂性,毫无意义。

However, you need to ask yourself some broader questions :
how you will ensure that caller and callee do communicate correctly?

但是,您需要问自己一些更广泛的问题:
您将如何确保调用方和被调用方正确通信?

That could be a follow-up on this question, or a different question...

那可能是对这个问题的跟进,或者是一个不同的问题......