对精炼工厂使用通用通用默认实现

时间:2014-08-15 08:57:06

标签: java generics

我有以下问题:

有一个通用的Factory接口

interface Factory<T> {
  T create();
}

现在我有两个T1和T2类,其中T2是T1

的细化
class T1 {
}

class T2 extends T1 {
}

和这两种类型的两家工厂:

interface T1Factory extends Factory<T1> {
  public T1 create();
}

interface T2Factory extends Factory<T2> {
  public T2 create();
}

对于这些工厂,将通过Generics提供默认实现:

class DefaultFactory<T, F extends Factory<T>> implements Factory<T> {
  private F factory;
  ...
  public T create()
  {
    return factory.create();
  }
}

应该用于实现T1和T2的工厂。

class DefaultT1Factory extends DefaultFactory<T1,T1Factory> {
}

class DefaultT2Factory extends DefaultFactory<T2,T2Factory> {
}

到这里它工作正常。现在问题。 因为T2是T1的细化,所以T2的工厂也可以用作T1的工厂。

这要求T2Factory来自T1Factory。如果我这样做,我不能使用DefaultFactory类来实现DefaultT2Factory,因为T2Factory不是Factory&lt; T2&gt;。 如果我将此关系添加到T2Factory的extends子句,我得到的错误是接口Factory不止一次被使用。但我需要Factory接口才能在默认实现中使用create方法。

从方法签名的角度来看,一切都很好。因此,我将默认实现的实现复制到工厂实现中。在我的情况下,这个编码非常大,我想避免代码重复。

知道如何规避这个问题。

3 个答案:

答案 0 :(得分:1)

我认为你的意思是

因为T2是T1的细化,所以T1的工厂也可以用作T2的工厂。 T1的工厂不应该用作T2的工厂,因为T1不是T2。但是T2是T1,因此T2的工厂可以安全地用作T1的工厂(或作为T1的工厂处理)

   public interface T1Factory<J extends T1> extends Factory<T1> {
             public T1 create();
        }

现在,当你实现这个界面时,很酷的说法是

public class Foo implements T1Factory<T2> {
         public T1 create(){
                    .....
          }
 }

现在基本上可以使用任何扩展或T1的类型参数化接口。在这种情况下,你说你想利用T2是一种T1关系。

希望有所帮助

答案 1 :(得分:0)

您可以使用wildcard来定义类似 Factory of T或任何T 子类型的内容。如果您将DefaultFactory的签名更改为

class DefaultFactory<T, F extends Factory<? extends T>> implements Factory<T> {

然后你应该能够拥有DefaultFactory<T1, T2Factory>

答案 2 :(得分:0)

我想我找到了一个解决方案,不是很好,但它似乎有效。之前的答案几乎正常,但使用 super 而不是 extends 。 重要的是能够重用实现。

当使用super。

放宽工厂元素的类型约束时,这应该是可能的
class DefaultFactory<T, F extends Factory<? super T>> {
  private F factory;

  @SuppressWarnings("unchecked")
  public T create()
  {
    return (T)factory.create();
  }
}

价格是调用create方法时不安全的类型,需要不安全的类型转换。但其余的似乎按预期工作。

T2Factory 因此必须扩展 T1Factory 。然而,遗憾的是它不是 Factory&lt; T2&gt; ,但这只是为了能够在默认实现中调用create方法返回正确的类型。为此目的,只需 Factory&lt; T1&gt; (这会导致所需的类型转换)。