通用接口
比方说,我想定义一个代表远程服务调用的接口。 现在,对远程服务的调用通常返回一些东西,但也可能包含input参数。 假设实现类通常只实现一种服务方法。 鉴于以上信息,下面是一个糟糕的devise(它不太对劲):
public interface IExecutesService<A,B> { public A executeService(); public A executeService(B inputParameter); }
现在,假设我使用一个类来执行该接口,该类使用input参数执行远程服务:
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 }
我有两个关于上述的问题:
- 如果要提供需要不同input参数和返回types的接口方法的子类,是否使用了通用接口(
IExecutesService<A,B>
)? - 我怎么能做到以上更好? 即我想我的服务执行者在一个共同的接口(
IExecutesService
); 然而,一个实现类通常只会实现其中的一个方法,而使用IllegalStateException真的很难看。 另外,IExecutesService<A,B>
的Btypes参数对于调用没有任何input参数的服务的实现类将是多余的。 这似乎也过分了,为两个不同的服务调用创build了两个单独的接口。
我会很感激你对此的评论。
干杯。
这里有一个build议:
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; } }
由于types擦除任何类只能实现其中之一。 这至less消除了冗余的方法。
这不是一个你提出的不合理的界面,但我不能100%确定它增加了什么价值。 您可能只想使用标准的Callable
接口。 它不支持参数,但该接口的一部分具有最小值(imho)。
这是另一个build议:
public interface Service<T> { T execute(); }
使用这个简单的接口, 你可以通过构造函数在具体的服务类中传递参数 :
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); } }
我会留下两个不同的界面。
你说'我想把我的服务执行者在一个通用的接口下进行分组……这似乎也过分了,为两个不同的服务调用创build了两个单独的接口……一个类将只实现这些接口之一'
不清楚是什么原因才有一个单一的界面。 如果你想用它作为标记,你可以直接利用注释。
还有一点是可能的情况是你的需求改变了,另一个签名的方法出现在界面上。 当然,也可以使用Adapter模式,但是看到这个特殊的类实现了接口,比如说三个方法,其中两个方法拖拽UnsupportedOperationException,会非常奇怪。 第四种方法可能会出现
作为一个严格符合你的问题的答案,我支持Cleytus的build议。
你也可以使用标记接口(没有方法),比如说DistantCall
,有几个子接口,它们都有你想要的特征。
- 通用接口将标记所有这些,以防万一你想为它们编写一些通用代码。
- 通过使用Cleytus的通用签名可以减less特定接口的数量。
“可重用”界面的例子:
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); } ....
更新回应OP评论
我没有想到任何在呼叫中的实例 。 我以为你的调用代码知道它调用的是什么,而你只需要在一个通用的接口中为一些通用代码组装几个远程调用( 例如,出于性能原因,审计所有远端调用 )。 在你的问题中,我没有看到调用代码是通用的:-(
如果是这样,我build议你只有一个接口,只有一个签名。 有几个只会带来更多的复杂性,没有什么。
但是,你需要问自己一些更广泛的问题:
你将如何确保呼叫者和被呼叫者正确地进行通信?
这可能是对这个问题的跟进,或者是一个不同的问题。
如果我理解正确,你想有一个类实现多个接口具有不同的input/输出参数? 这在Java中不起作用,因为generics是通过擦除来实现的。
Javagenerics的问题是generics实际上只是编译器的魔力。 在运行时,这些类不会保留任何关于genericstypes(类types参数,方法types参数,接口types参数)的types信息。 因此,即使可能有特定方法的重载,也不能将它们绑定到只有通用types参数不同的多个接口实现。
一般来说,我可以看到为什么你认为这个代码有一种气味。 但是,为了给您提供更好的解决scheme,有必要了解您的需求。 为什么你想首先使用通用接口?