【问题标题】:Java generics in pipeline architecture管道架构中的 Java 泛型
【发布时间】:2016-11-29 21:35:49
【问题描述】:

我有一个基本抽象类PipelineStage,它具有以下定义:

public abstract class PipelineStage<I, O> implements Runnable {

    ...

    public abstract O step(I input);

    ...

}

然后我有许多具体的管道阶段,其定义如下:

public class ConcreteStage extends PipelineStage<InputContextClass, OutputContextClass> {

    ...

    @Override
    public OutputContextClass step(InputContextClass input) {
        input.someMethod();
        ...
        return new OutputContextClass();
    }

    ...

}

但是,这导致了一种僵化的设计,其中:

  1. 上下文类与使用它们的阶段紧密耦合。

  2. 每个阶段都需要定义两个完整的接口,定义输入和输出类的所有属性。

我想通过使用指定上下文类属性的通用接口来改进此设计,然后 ConcreteStage 将指定它的输入和输出上下文类必须扩展的接口。

但是,我不知道如何以编译器喜欢的方式执行此操作。

例如:

public class ConcreteStage extends PipelineStage<I extends Interface1 & Interface2, 
    O extends Interface2 & Interface3> {

    ...

    @Override
    public O step(I input) {
        input.someMethodFromInterface1();
        input.someMethodFromInterface2();
        ...
        // OutputContextClass extends Interface2 & Interface3
        return new OutputContextClass();
    }

    ...

}

但是,这不会编译,表明需要导入类 I

通配符也不起作用,例如No wildcard expected

有没有人对如何以一种简洁、灵活的方式实现这一点有任何建议?非常感谢!

【问题讨论】:

  • 只是猜测,IO 现在不应该成为ConcreteStage 的泛型参数,比如ConcreteStage&lt;I, O&gt;
  • @DanilGaponov 你的想法和安迪·特纳的回答一样,我回答了他为什么我认为这不是一个完全合适的解决方案。

标签: java generics interface architecture


【解决方案1】:

您需要将类型变量声明放在类上,而不是超类上:

public static class ConcreteStage<
          I extends Interface1 & Interface2, O extends Interface2 & Interface3>
      extends PipelineStage<I, O> {

【讨论】:

  • 这个问题是,ConcreteStage 的实例化需要指定的那些类型,而实际上这更多的是实现细节。类的用户不需要知道它使用什么类在管道内进行通信。
  • 我猜这是因为管道的用户创建了一个Pipeline 对象,然后创建了多个PipelineStage 实例,然后创建了Pipeline.add(PipelineStage)。相反,如果用户没有直接实例化 PipelineStage 实例,而只是指出他们想要使用哪些实例(例如使用映射到具体类的枚举),那么 Pipeline 类可以进行实例化并在一定程度上保护实施细节。
  • 你不能同时拥有它:你可以是通用的,并且让用户指定输入和输出类型;或者您可以通过在extends PipelineStage&lt;InputType, OutputType&gt; 中声明具体类型来具体化,并且让用户不需要指定它们,但无法更改它们。
  • (好吧,我想您可以使用第三种方式,并使用原始类型。但这样做特别不明智,因为您会失去类型安全性)
  • 我想我希望包知道上下文类型,但管道的外部用户不知道。你会说使用枚举来指定你想要在管道中的哪些阶段是个好主意吗?编辑:实际上,让用户决定在阶段之间传递哪些类可能是确保用户检查两个连续阶段之间是否具有相同类型的好方法。所以也许隐藏它不是最好的主意?
【解决方案2】:

您还可以创建一个接口,将输入接口组合在一起interface InputInterface12 extends InputInterface1, InputInterface2 {}class ConcreteStage extends PipelineStage&lt;InputInterface12, OutputInterface12&gt; {...}

【讨论】:

  • 我实际上考虑过,这是一个有效的解决方案。缺点是您将拥有大约 2 倍于管道阶段的上下文接口(取决于您可以重用的程度),这并不是特别方便,因为我有大约 12 个阶段并且还在不断增长。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多