2015-11-02 160 views
-2

请注意更新,我的问题没有明确阐述。对不起。使用Java泛型的接口/抽象类的构造函数

让我们假设我们有下面的代码:

class Foo extends/implements AnAbstractClass/AnInterface { /* to make sure the constructor with int as input is implemented */ 
    Foo(int magicInt) { magicInt + 1; /* do some fancy calculations */ } 
} 

class Bar extends/implements AnAbstractClass/AnInterface { /* to make sure the constructor with int as input is implemented */ 
    Bar(int magicInt) { magicInt + 2; /* do some fancy calculations */ } 
} 

class Factory<T extends/implements AnAbstractClass/AnInterface> { 
    int magicInt = 0; 

    T createNewObject() { 
     return new T(magicInt) // obviously, this is not working (*), see below 
    } 
} 

/* how it should work */ 
Factory<Foo> factory = new Factory<Foo>(); 
factory.createNewObject() // => Foo with magicInt = 1 

Factory<Bar> factory = new Factory<Bar>(); 
factory.createNewObject() // => Bar with magicInt = 2 

(*)位置,我不知道该怎么办。我怎样才能确保这样的签名的构造函数...(int magicInt)被实现?我不能定义

  1. 具有一定签名的构造函数中的接口

    interface AnInterface { 
        AnInterface(int magicInt); 
    } 
    
  2. 一个抽象类,执行一定的构造

    abstract class AnAbstractClass { 
        abstract AnAbstractClass(int magicInt); 
    } 
    

    这显然是缺失的要求在子类中实现构造函数:

    abstract class AnAbstractClass { 
        AnAbstractClass(int magicInt) {} 
    } 
    
  3. an interfaceabstract class一个静态方法,它可以覆盖为AnInterfaceAnAbstractClass每个实现(我觉得一个工厂模式)

什么是要走的路?

+0

我不明白你的问题是什么......你究竟想达到什么目的,为什么它不工作? –

+1

我认为你想要的结果代码有些奇怪。 'SampleSource'具有扩展'SampleFactory'的参数。然后在'getCurrentSample()'中调用这个示例工厂来创建一个与'SampleFactory'应该具有相同类型的示例。所以创建一个样本给你一个样本工厂? – Timo

+1

那么因为Java 8静态方法在接口中是允许的。 – Flown

回答

1

这听起来像是你真的在寻找一种解决方案,如何在没有一堆if/else块的情况下编写一个通用的工厂方法,并且不需要在每个类中写一个方法。因此,请考虑使用以下代码中的反射:

interface Interface { 
} 

class Foo implements Interface { 
    Foo(int magicInt) { magicInt = magicInt + 1; /* do some fancy calculations */ } 
} 

class Bar implements Interface { 
    Bar(int magicInt) { magicInt = magicInt + 2; /* do some fancy calculations */ } 
} 

class Factory<T extends Interface> { 
    int magicInt = 0; 

    public T createNewObject(Class<T> typeToMake) { 
     try { 
      T t = createNewObjectWithReflection(typeToMake); 
      return t; 
     } catch (Exception e) { 
      throw new RuntimeException("Construction failed!", e); 
     } 
    } 

    private T createNewObjectWithReflection(Class<T> typeToMake) throws Exception { 
     // find the constructor of type to make with a single int argument 
     Constructor<T> magicIntConstructor = typeToMake.getDeclaredConstructor(Integer.TYPE); 
     // call the constructor with the value of magicInt 
     T t = magicIntConstructor.newInstance(magicInt); 
     return t; 
    } 
} 

/* Name of the class has to be "Main" only if the class is public. */ 
class Ideone 
{ 
    public static void main (String[] args) throws java.lang.Exception 
    { 
     Factory<Foo> fooFactory = new Factory<Foo>(); 
     Foo foo = fooFactory.createNewObject(Foo.class); 
     System.out.println(foo); 

     Factory<Bar> barFactory = new Factory<Bar>(); 
     Bar bar = barFactory.createNewObject(Bar.class); 
     System.out.println(bar); 
    } 
} 

您可以run the demo at IDEOne here

+0

是的,这是我正在寻找的解决方案。但是在Java中是丑陋的? –

+0

非常好,是的。我编辑了代码帖子来整理代码,但总体来说,反思并不常见。 – entpnerd

+0

工厂本身没有通用性。在工厂中通用该方法就足够了。我也认为你可以使用TypeLiteral和Guice的Factory绑定来实现相同的功能,使用辅助注入。这使得你的代码更清洁一些。 –

4

我真的没有看到你的想法工作。

我觉得它打破了Factory模式的概念,该模式真正旨在让负责创建单个类的实例的方法see ref

我宁愿:

  1. 在你的工厂类一个方法,要构造
  2. 和可能,而不必在构造函数中的具体行为每种类型的对象,有一个公共的构造父类抽象类和一个抽象方法,它可以做花式计算(但这真的是样式偏好)。

这将导致沿着线的东西:

abstract class AbstractSample { 
    private int magicInt; 

    public AbstractSample(int magicInt) { 
     this.magicInt = magicInt; 
    } 

    protected int getMagicInt() { 
     return magicInt; 
    } 

    public abstract int fancyComputation(); 

} 

public class Foo extends AbstractSample { 
    public Foo(int magicInt) { 
     super(magicInt) 
    } 

    public int fancyComputation() { 
     return getMagicInt() + 1; 
    } 
} 

public class Bar extends AbstractSample { 
    public Bar(int magicInt) { 
     super(magicInt) 
    } 

    public int fancyComputation() { 
     return getMagicInt() + 2; 
    } 
} 

public class SampleFactory { 
    private int magicInt = 0; 

    public Foo createNewFoo() { 
     return new Foo(magicInt); 
    } 

    public Bar createNewBar() { 
     return new Bar(magicInt); 
    } 
} 

回答到以前的版本问题可能会被删除的,如果更新的答案满足OP

这是绝对奇怪的类都扩展Sample和执行SampleFactory ...

我宁愿有沿着线的东西:

class Sample { 
    protected Sample() { /* ... */ } 
} 

interface SampleFactory<T extends Sample> { 
    T createSample(final int i); 
} 

class AccelerationSample extends Sample { 
    public AccelerationSample(final int i) { /* do some fancy int calculations*/ } 
} 

class OrientationSample extends Sample { 
    private OrientationSample (final int i) { /* do some fancy int calculations*/ } 
} 

abstract class SampleSource<T extends Sample> { 
    int magicInt; 
    SampleFactory<T> sampleFactory; 
    T getCurrentSample() { 
     return sampleFactory.createSample(magicInt); 
    } 
} 

class AccelerationSampleSource extends SampleSource<AccelerationSample> { 
    SampleFactory<AccelerationSample> sampleFactory = new SampleFactory<> { 
     public AccelerationSample createSample(final int i) { 
      return new AccelerationSample(i); 
     } 
    } 
} 

class OrientationSampleSource extends SampleSource<OrientationSample> { 
    SampleFactory<OrientationSample> sampleFactory = new SampleFactory<> { 
     public OrientationSample createSample(final int i) { 
      return new OrientationSample(i); 
     } 
    } 
} 

这将是清洁还是使用命名的工厂,如

public AccelerationSampleFactory implements SampleFactory<AccelerationSample> { 
    public AccelerationSample createSample(final int i) { 
     return new AccelerationSample(i); 
    } 
} 

然后你可以作为

class AccelerationSampleSource extends SampleSource<AccelerationSample> { 
    SampleFactory<AccelerationSample> sampleFactory = new AccelerationSampleFactory(); 
} 
使用
+0

确实,很抱歉...无法在界面中定义静态方法...我已经相应地更新了我的答案。 (如果你希望它是通用的,那么不需要该方法是静态的)。 – Thomas

+1

(更具体地说,在java 8中,你可以在接口中有静态方法,但绝对不是静态方法返回一个实例类型) – Thomas

+0

感谢你的解决方案,但是我有一个静态工厂方法为每个类我会有几十个这样的)。因此我认为泛型被引入。 :) –

2

正如你所指出的那样,这个问题中的3个想法都不被支持(一个带有certa的构造函数在一个接口签名,一个抽象类执行特定的构造函数,或静态方法的接口或抽象类)

然而,可以定义的接口(或抽象类内)这是一个工厂的类型时最终想要。

public interface AnInterface { 
    int fancyComputation(); 
} 
public interface IFooBarFactory<T extends AnInterface> { 
    T create(int magicNumber); 
} 

IFooBarFactory具有2个具体实现

public class BarFactory implements IFooBarFactory<Bar> { 
    public Bar create(int magicNumber) { 
     return new Bar(magicNumber); 
    } 
} 
public class FooFactory implements IFooBarFactory<Foo> { 
    public Foo create(int magicNumber) { 
     return new Foo(magicNumber); 
    } 
} 

然后使用策略模式(https://en.wikipedia.org/wiki/Strategy_pattern)检索正确的工厂。然后使用这个具有已知接口的工厂来制造具有正确值的对象(以及制造对象所需的任何附加值)。

FooBarFactory fooBarFactory = new FooBarFactory(); 
    IFooBarFactory<T> factory = fooBarFactory.createFactory(typeOfAnInterface); 
    T impl = factory.create(magicNumber); 

随着conrete实现

public class Bar implements AnInterface { 
    private final int magicInt; 
    public Bar(int magicInt) { 
     this.magicInt = magicInt; 
    } 
    public int fancyComputation() { 
     return magicInt + 2; 
    } 
} 
public class Foo implements AnInterface { 
    private final int magicInt; 
    public Foo(int magicInt) { 
     this.magicInt = magicInt; 
    } 
    public int fancyComputation() { 
     return magicInt + 1; 
    } 
} 

以下代码:

public static void main(String ... parameters) { 
    test(Foo.class); 
    test(Bar.class); 
} 
private static <T extends AnInterface> void test(Class<T> typeOfAnInterface) { 
    T impl = createImplForAnInterface(typeOfAnInterface, 10); 
    System.out.println(typeOfAnInterface.getName() + " produced " + impl.fancyComputation()); 
} 
private static <T extends AnInterface> T createImplForAnInterface(Class<T> typeOfAnInterface, int magicNumber) { 
    FooBarFactory fooBarFactory = new FooBarFactory(); 
    IFooBarFactory<T> factory = fooBarFactory.createFactory(typeOfAnInterface); 
    T impl = factory.create(magicNumber); 
    return impl; 
} 

打印

Foo produced 11 
Bar produced 12 

这提供了许多益处超过与内省ö的溶液r静态工厂。调用者不需要知道如何制造任何对象,调用者也不需要知道或关心方法是何时使用“正确”方法来检索正确类型。所有呼叫者只需呼叫一个公共/已知组件,即返回“正确”的工厂。这使得你的调用者更清洁,因为他们不再与FooBar类型的AnInterface的具体实现紧密耦合。他们只需要关心“我需要实现AnInterface,它会消耗(或处理)这种类型。”我知道这意味着你有两个“工厂”类。一个检索正确的工厂,另一个实际负责创建具体类型Foo和Bar。但是,您可以通过附加的抽象层从调用方隐藏此实现细节(请参阅createImplForAnInterface方法)。

如果您通常使用某种形式的依赖注入,此方法将特别有用。我的建议与Guice的辅助注射(https://github.com/google/guice/wiki/AssistedInject)或春季的类似想法(Is it possible and how to do Assisted Injection in Spring?)完全相符。

这意味着你需要有几个工厂类(或Guice的依赖注入绑定规则),但每个类都很小,很简单,而且易于维护。然后编写一个小测试,检索实现AnInterface的所有类,并验证实现策略模式的组件是否覆盖了所有情况(通过反射 - 我将使用org.reflections中的Reflections类:reflections)。这为您提供了一种可用的代码抽象,通过减少冗余代码,放松组件的紧密耦合,而不是牺牲多态性来简化这些对象的使用。