2

假设我有这两个继承层次结构:

class EntityA { ... }
class EntityB extends EntityA { ... }

class EntityAPrime extends AbstractPrime<EntityA> { ... }
class EntityBPrime extends EntityAPrime { ... }

我也想要协变返回类型:

public class EntityA {
  public EntityAPrime prime() {
    return new EntityAPrime();
  }
}

public class EntityB extends EntityA {
  @Override
  public EntityBPrime prime() {
    return new EntityBPrime();
  }
}

到目前为止,一切都很好。

问题是我想EntityBPrime最终扩展AbstractPrime<EntityB>,但由于它扩展EntityAPrime它最终扩展AbstractPrime<EntityA>

我可以制作EntityAPrimeEntityBPrime通用,但后来我失去了协变返回类型:

public class EntityA {
  public EntityAPrime<EntityA> prime() {
    return new EntityAPrime();
  }
}

public class EntityB extends EntityA {
  @Override
  public EntityBPrime<B> prime() {  // ERROR: EntityBPrime extends EntityAPrime
    return new EntityBPrime();      // but can't substitute <EntityB> for <EntityA>
  }
}

如果我返回一个绑定的通配符,一切都会正常工作,但有与之相关的缺点,我将无法调用特定的 setter on AbstractPrime

EntityA我的另一个想法是使EntityB它们自己通用。

public class EntityA<T extends EntityA> {
  public EntityAPrime<T> prime() { ... }
}

public class EntityB<T extends EntityB> extends EntityA<T> {
    @Override
    public EntityBPrime<T> prime() { ... }
}

这应该可行,但我认为它会变得混乱(我们有超过 100 个实体会使用类似的模式)。

那么,有没有办法:

  • 保持协变回报
  • EntityA不要在and上使用泛型EntityB
  • 没有prime()返回绑定通配符
  • EntityBPrime最终扩展AbstractPrime<EntityB>而不是AbstractPrime<EntityA>

注意:主要类是生成的代码,但我可以控制生成的代码。

4

2 回答 2

1

首先,您的接口和类都被称为Aand有点令人困惑B。因此,我将这些类分别重命名为AImplBImpl。此外,您的课程APrimeBPrime没有输入(它们需要输入),所以我假设它们是分别输入的<T extends A><T extends B>如果我误解了您的意图/目标/要求,我深表歉意)。

private interface A {}
private interface B extends A {}
private abstract class AbstractPrime<T extends A>{}
private class APrime<T extends A> extends AbstractPrime<T>{}
private class BPrime<T extends B> extends APrime<T>{}
private class AImpl {...}
private class BImpl {...}

正如您所考虑的,我的第一直觉是在接口上键入实现。这会起作用:

private class AImpl<T extends A> {
  public APrime<T> prime(){
    return new APrime<>();
  }
}

private class BImpl<T extends B> extends AImpl<T> {
  public BPrime<T> prime(){
    return new BPrime<>();
  }
}

但是,如果您输入APrime了 on<T extends A>BPrimeon <T extends B>,是否需要输入 of 的返回类型prime()?以下解决方案可能对您有用吗?

class APrime<T extends A> extends AbstractPrime<T>{}
class BPrime<T extends B> extends APrime<T>{}

public class AImpl {
  public APrime prime(){
    return new APrime<>();
  }
}

public class BImpl extends AImpl {
  public BPrime prime(){
    return new BPrime<>();
  }
}

我想这个问题的答案在某种程度上是您是否设想需要以下内容:

private interface C extends B {}

public void main(String[] args) {
  BPrime<C> prime = new BImpl<C>().prime(); // do you need this?
  BPrime<B> prime = new BImpl<>().prime(); // do you need this?


  BPrime prime = new BImpl().prime(); or is this sufficient...?
}
于 2013-08-27T21:42:50.827 回答
1

正如我在评论中提到的,有很多地方省略了类型参数,这使得整个故事看起来不正确。

首先,您的 Prime 至少应该如下所示:

class EntityAPrime<T extends EntityA> extends AbstractPrime<T> {}

class EntityBPrime<T extends EntityB> extends EntityAPrime<T> {}

然后问题来了你的实体

class EntityA {
  public EntityAPrime<????> prime();  <- What should be the reasonable type param here?
}

class EntityB extends EntityA {
  public EntityBPrime<????> prime();  <- Same here
}

答案取决于您的设计。

我看不出你的第二个选择比你原来的那个更乱(因为原来的那个真的很乱)

您可以考虑这一点(未经测试,是否正确很大程度上取决于您的设计,但至少 type params 在我看来是合理的):

public class Entity<T> {
  public Prime<T> prime();
}

public class AbstractEntityA<T extends EntityA> extends Entity<T> {
  @Override
  public AbstractAPrime<T> prime();
}

public class EntityA extends AbstractEntityA<EntityA>{
  public EntityAPrime prime() { ... }
}

public class EntityB extends AbstractEntityA<EntityB> {
  public EntityBPrime prime() {...}
}


public class AbstractAPrime<T extends EntityA> extends AbstractPrime<T> {}

public class EntityAPrime extends AbstractAPrime<EntityA>{}
public class EntityBPrime extends AbstractAPrime<EntityB>{}

简而言之,将原始 EntityA 中的内容移动到一个抽象类,由 EntityA(主要是一个普通的扩展)和 EntityB(覆盖并添加更多东西)对其进行扩展。同样适用于 Prime。

于 2013-08-28T04:34:32.377 回答