使用Java泛型的接口/抽象类的构造函数
请注意更新,我的问题没有明确阐述。对不起。使用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)
被实现?我不能定义
-
具有一定签名的构造函数中的接口
interface AnInterface { AnInterface(int magicInt); }
-
一个抽象类,执行一定的构造
abstract class AnAbstractClass { abstract AnAbstractClass(int magicInt); }
这显然是缺失的要求在子类中实现构造函数:
abstract class AnAbstractClass { AnAbstractClass(int magicInt) {} }
内an interface或abstract class一个静态方法,它可以覆盖为
AnInterface
或AnAbstractClass
每个实现(我觉得一个工厂模式)
什么是要走的路?
这听起来像是你真的在寻找一种解决方案,如何在没有一堆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);
}
}
是的,这是我正在寻找的解决方案。但是在Java中是丑陋的? –
非常好,是的。我编辑了代码帖子来整理代码,但总体来说,反思并不常见。 – entpnerd
工厂本身没有通用性。在工厂中通用该方法就足够了。我也认为你可以使用TypeLiteral和Guice的Factory绑定来实现相同的功能,使用辅助注入。这使得你的代码更清洁一些。 –
我真的没有看到你的想法工作。
我觉得它打破了Factory
模式的概念,该模式真正旨在让负责创建单个类的实例的方法see ref。
我宁愿:
- 在你的工厂类一个方法,要构造
- 和可能,而不必在构造函数中的具体行为每种类型的对象,有一个公共的构造父类抽象类和一个抽象方法,它可以做花式计算(但这真的是样式偏好)。
这将导致沿着线的东西:
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();
}
使用
正如你所指出的那样,这个问题中的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)。这为您提供了一种可用的代码抽象,通过减少冗余代码,放松组件的紧密耦合,而不是牺牲多态性来简化这些对象的使用。
我不明白你的问题是什么......你究竟想达到什么目的,为什么它不工作? –
我认为你想要的结果代码有些奇怪。 'SampleSource'具有扩展'SampleFactory'的参数。然后在'getCurrentSample()'中调用这个示例工厂来创建一个与'SampleFactory'应该具有相同类型的示例。所以创建一个样本给你一个样本工厂? – Timo
那么因为Java 8静态方法在接口中是允许的。 – Flown