interface/abstract class 使用 Java 泛型的构造函数
Constructor to interface/abstract class using Java generics
请注意更新,我的问题没有明确表述。对不起。
让我们假设我们有以下代码:
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);
}
一个抽象 class 强制执行某个构造函数
abstract class AnAbstractClass {
abstract AnAbstractClass(int magicInt);
}
这显然缺少在子classes:
中实现构造函数的要求
abstract class AnAbstractClass {
AnAbstractClass(int magicInt) {}
}
an interface or abstract class中的静态方法,可以为AnInterface
或AnAbstractClass
的每个实现覆盖(我想到了工厂模式)
要走的路是什么?
我真的不认为你的想法可行。
我觉得它打破了 Factory
模式的概念,它的真正目的是让一个方法负责创建单个 class see ref.
的实例
我宁愿:
- 在你的工厂中为你想要构造的每种类型的对象准备一个方法class
- 并且可能不是在构造函数中具有特定行为,而是在父抽象中有一个通用构造函数 class 和一个进行花式计算的抽象方法(但这确实是风格偏好)。
这会导致以下内容:
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
,可能会被删除
classes 既扩展了 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();
}
正如您所指出的,none 问题中的 3 个想法得到了支持(在接口中具有特定签名的构造函数,强制执行特定构造函数的抽象 class,或静态接口或抽象中的方法 class)
但是,您可以定义一个接口(或抽象 class),它是您最终想要的类型的工厂。
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);
有了具体的实现
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
与使用内省或静态工厂的解决方案相比,这提供了许多好处。调用者不需要知道如何制造任何对象,调用者也不需要知道或关心何时使用 "correct" 方法来检索正确的类型。所有调用者只需调用一个 public/known 组件,即 returns "correct" 工厂。这使您的调用者更清晰,因为它们不再与 FooBar 类型的 AnInterface 的具体实现紧密耦合。他们只需要关心 "I need an implementation of AnInterface, which consumes (or processes) this type." 我知道这意味着你有两个 "factory" class。一个检索正确的工厂,另一个实际上负责创建具体类型 Foo 和 Bar。但是,您通过额外的抽象层(请参阅 createImplForAnInterface 方法)向调用者隐藏此实现细节。
如果您通常使用某种形式的依赖注入,这种方法将特别有用。我的建议完全符合 Guice 的辅助注射 (https://github.com/google/guice/wiki/AssistedInject) or a similar idea in Spring (Is it possible and how to do Assisted Injection in Spring?)。
这意味着您需要多个工厂 classes(或 Guice 的依赖注入绑定规则),但每个 classes 都很小、简单且易于维护。然后你编写一个小测试来检索所有实现 AnInterface 的 classes 并验证你实现策略模式的组件是否涵盖了所有情况(通过反射 - 我会在 org.reflections:反射)。这为您提供了一个可用的代码抽象,通过减少冗余代码、放松组件的紧密耦合以及不牺牲多态性来简化这些对象的使用。
听起来您真的在寻找一种解决方案来解决如何在没有一堆 if/else 块并且不在每个 class 中编写一个通用工厂方法的方法。因此,请考虑在以下代码中使用反射:
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);
}
}
请注意更新,我的问题没有明确表述。对不起。
让我们假设我们有以下代码:
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); }
一个抽象 class 强制执行某个构造函数
abstract class AnAbstractClass { abstract AnAbstractClass(int magicInt); }
这显然缺少在子classes:
中实现构造函数的要求abstract class AnAbstractClass { AnAbstractClass(int magicInt) {} }
an interface or abstract class中的静态方法,可以为
AnInterface
或AnAbstractClass
的每个实现覆盖(我想到了工厂模式)
要走的路是什么?
我真的不认为你的想法可行。
我觉得它打破了 Factory
模式的概念,它的真正目的是让一个方法负责创建单个 class see ref.
我宁愿:
- 在你的工厂中为你想要构造的每种类型的对象准备一个方法class
- 并且可能不是在构造函数中具有特定行为,而是在父抽象中有一个通用构造函数 class 和一个进行花式计算的抽象方法(但这确实是风格偏好)。
这会导致以下内容:
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
,可能会被删除classes 既扩展了 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();
}
正如您所指出的,none 问题中的 3 个想法得到了支持(在接口中具有特定签名的构造函数,强制执行特定构造函数的抽象 class,或静态接口或抽象中的方法 class)
但是,您可以定义一个接口(或抽象 class),它是您最终想要的类型的工厂。
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);
有了具体的实现
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
与使用内省或静态工厂的解决方案相比,这提供了许多好处。调用者不需要知道如何制造任何对象,调用者也不需要知道或关心何时使用 "correct" 方法来检索正确的类型。所有调用者只需调用一个 public/known 组件,即 returns "correct" 工厂。这使您的调用者更清晰,因为它们不再与 FooBar 类型的 AnInterface 的具体实现紧密耦合。他们只需要关心 "I need an implementation of AnInterface, which consumes (or processes) this type." 我知道这意味着你有两个 "factory" class。一个检索正确的工厂,另一个实际上负责创建具体类型 Foo 和 Bar。但是,您通过额外的抽象层(请参阅 createImplForAnInterface 方法)向调用者隐藏此实现细节。
如果您通常使用某种形式的依赖注入,这种方法将特别有用。我的建议完全符合 Guice 的辅助注射 (https://github.com/google/guice/wiki/AssistedInject) or a similar idea in Spring (Is it possible and how to do Assisted Injection in Spring?)。
这意味着您需要多个工厂 classes(或 Guice 的依赖注入绑定规则),但每个 classes 都很小、简单且易于维护。然后你编写一个小测试来检索所有实现 AnInterface 的 classes 并验证你实现策略模式的组件是否涵盖了所有情况(通过反射 - 我会在 org.reflections:反射)。这为您提供了一个可用的代码抽象,通过减少冗余代码、放松组件的紧密耦合以及不牺牲多态性来简化这些对象的使用。
听起来您真的在寻找一种解决方案来解决如何在没有一堆 if/else 块并且不在每个 class 中编写一个通用工厂方法的方法。因此,请考虑在以下代码中使用反射:
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);
}
}