【问题标题】:How to force client to implement multiple generic interfaces with same type [duplicate]如何强制客户端实现多个具有相同类型的通用接口[重复]
【发布时间】:2019-05-11 12:26:55
【问题描述】:

假设我有一些通用接口

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 使用原始类型?
  • 因为我想为不同的类型执行同样的事情
  • 然后创建不同的实例?
  • @MuratKaragöz 如果没有原始编排器,您将无法定义服务的原始实例变量
  • 使用抽象工厂模式修复了设计

标签: java oop design-patterns interface abstract-class


【解决方案1】:

禁止原始类型。

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

这应该会产生一个警告。不要产生警告。

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

【讨论】:

  • 警告经常被忽略,我可以编译失败吗
  • 将警告视为编译时错误。如果您忽略类型警告,那么您为什么不期望运行时类型错误?我的意思是,如果您愿意,可以写 (Orchestrator&lt;String&gt;)(Orchestrator)new Orchestrator&lt;Integer&gt;(...),但不要写。
  • @aatishrana 你忽略了警告。这就是它崩溃的原因..
  • @TomHawtin-tackline 还有其他方法来设计这个用例吗?对多个具体但类型相同的混凝土执行相同的功能,并进行类型检查
  • @aatishrana 泛型用于编译时。它们通常不适用于运行时实例(有特殊情况)。
【解决方案2】:

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

您使用的不是 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 abstract 并且扩展它的类应该指定类型。例如,

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);

【讨论】:

    猜你喜欢
    • 2013-07-03
    • 2013-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-27
    • 2020-07-25
    相关资源
    最近更新 更多