如何强制客户端实现具有相同类型的多个通用接口



假设我有一些通用接口

public interface Service<T> {
T getData();
}
public interface ResponseBuilder<T> {
void build(T response);
}

以及一些使用这些接口的通用类

public class Orchestrator<T> {
private Service<T> service;
private List<ResponseBuilder<T>> responseBuilders;
public Orchestrator(Service<T> serviceImpl, List<ResponseBuilder<T>> buildersImpl){
this.service = serviceImpl;
this.responseBuilders = buildersImpl; 
}
public void execute() {
T response = service.getData();
responseBuilders
.stream()
.map(builder -> builder.build(response))
.forEach(data -> storageUtil.upload(data));
}
}

当客户端开发人员要使用这些API时,我如何强制他/她在这些通用接口的具体实现中传递相同的类型,以避免类型不匹配异常。

Orchestrator在未指定其类型的情况下创建的实例可以采用不同的类型作为参数例如:-

public class App{
public static void main(String[] args){
ResponseBuilder<String> response1 = new SomeImpl(); // type STRING
Service<Integer> service = new SomeServiceImpl(); // type INTEGER
// completely valid and compilable code, will throw ex at runtime
Orchestrator orch = new Orchestrator(service, Arrays.asList(response1));
}
}

什么是更好的设计?

不允许原始类型。

Orchestrator orch = new Orchestrator(service, Arrays.asList(response1));

这应该是一个警告。不要发出警告。

Orchestrator<T> orch = new Orchestrator<T>(service, Arrays.asList(response1));

我认为您所做的是正确的,但只是缺少正确利用通用功能的部分。

您没有使用Orchestrator T.类型

当您接受其他对象的泛型类型实例时,您可以通过继承验证它们是否属于相同的泛型类型。

例如,在Orchestrator类中,您应该执行以下操作:

public class Orchestrator<T> {
private Service<? extends T> service;
private List<? extends  ResponseBuilder<? extends  T>> responseBuilders;
public Orchestrator(Service<? extends T> service, List<? extends  ResponseBuilder<? extends  T>> buildersImpl){
this.service = service;
this.responseBuilders = buildersImpl;
}
}

这里不匹配的类型会在编译时引发错误。如果Orchestrator的实例是用这样的类型定义创建的,这将起作用

= new Orchestrator<String>(....);

此外,如果我们只有几种类型的泛型可能性,那么最好的方法是使Orchestrator抽象,并且扩展它的类应该指定类型。例如

public class StringOrchestrator extends Orchestrator<String> {
public StringOrchestrator(Service<? extends String> service,
List<? extends ResponseBuilder<? extends String>> buildersImpl) {
super(service, buildersImpl);
}
}

然后,用一些具体的实现实例化Orchestrator,这些实现在意义上不是通用的,比如:

Orchestrator<String> orchestrator = new StringOrchestrator(service,list);

最新更新