反射而不是工厂模式?
Reflection instead of Factory pattern?
以下是我如何在运行时基于我要调用的子class构造函数对象(以避免每次我想添加新子时都必须更新工厂class class):
import java.lang.reflect.InvocationTargetException;
public class Main{
private static final class X{}
private static abstract class A{
public A(X x){}
public static A newInstance(Class<? extends A> subType, X x) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
return subType.getConstructor(X.class).newInstance(x);
}
}
private static final class A_1 extends A{
public A_1(X x){
super(x);
//...
}
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
for(int i = 0; i < 1000; i++){
X x = new X();
long t = System.currentTimeMillis();
A a = A.newInstance(A_1.class, x);
t = System.currentTimeMillis() - t;
System.out.println(t);
}
}
}
起初我以为它会很慢,但第一次迭代我得到 1ms,任何连续实例化得到 0。
我的应用程序部署后是否会出现类似的行为(此处我简化了过程,但在我的应用程序上下文中几乎没有任何困难)。
采用这种技术的优缺点是什么?
反思几乎总是最糟糕的做事方式。
- 反射很慢。即时编译器通常无法在运行时对其进行优化。
- 反射容易出错。编译器无法验证反射代码的正确性。在您的情况下,编译器无法保证
subType
具有采用单个 X 参数的构造函数。
- 反射很难在代码中遵循,因此很难维护。
在你的例子中,你想要一个代表子类构造函数的 Function:
public static A newInstance(Function<? super X, ? extends A> constructor, X x) {
return constructor.apply(x);
}
您可以使用方法引用调用该方法:
A a = newInstance(A_1::new, x);
当然,反射不是基本情况(但它确实有效)。我提议使用 Factory
来保存所有工厂方法来创建所需的类型。只需在不更改实现的情况下添加新工厂的功能即可。
我提供了一个解决方案而不改变你的主要API public static <T extends Base> T newInstance(Class<T> subType, X x)
.
public class Main {
public static void main(String[] args) throws Exception {
Factory.add(OneBase.class, OneBase::new);
Factory.add(TwoBase.class, TwoBase::new);
OneBase oneBase = Factory.newInstance(OneBase.class, new X());
TwoBase twoBase = Factory.newInstance(TwoBase.class, new X());
}
}
final class Factory {
private static final Map<Class<? extends Base>, Function<X, ? extends Base>> FACTORIES = new HashMap<>();
public static void add(Class<? extends Base> subType, Function<X, ? extends Base> factory) {
FACTORIES.put(subType, factory);
}
public static <T extends Base> T newInstance(Class<T> subType, X x) {
return (T)FACTORIES.get(subType).apply(x);
}
}
final class X {}
abstract class Base {
protected Base(X x) {}
}
final class OneBase extends Base {
public OneBase(X x) {
super(x);
}
}
final class TwoBase extends Base {
public TwoBase(X x) {
super(x);
}
}
以下是我如何在运行时基于我要调用的子class构造函数对象(以避免每次我想添加新子时都必须更新工厂class class):
import java.lang.reflect.InvocationTargetException;
public class Main{
private static final class X{}
private static abstract class A{
public A(X x){}
public static A newInstance(Class<? extends A> subType, X x) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
return subType.getConstructor(X.class).newInstance(x);
}
}
private static final class A_1 extends A{
public A_1(X x){
super(x);
//...
}
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
for(int i = 0; i < 1000; i++){
X x = new X();
long t = System.currentTimeMillis();
A a = A.newInstance(A_1.class, x);
t = System.currentTimeMillis() - t;
System.out.println(t);
}
}
}
起初我以为它会很慢,但第一次迭代我得到 1ms,任何连续实例化得到 0。
我的应用程序部署后是否会出现类似的行为(此处我简化了过程,但在我的应用程序上下文中几乎没有任何困难)。
采用这种技术的优缺点是什么?
反思几乎总是最糟糕的做事方式。
- 反射很慢。即时编译器通常无法在运行时对其进行优化。
- 反射容易出错。编译器无法验证反射代码的正确性。在您的情况下,编译器无法保证
subType
具有采用单个 X 参数的构造函数。 - 反射很难在代码中遵循,因此很难维护。
在你的例子中,你想要一个代表子类构造函数的 Function:
public static A newInstance(Function<? super X, ? extends A> constructor, X x) {
return constructor.apply(x);
}
您可以使用方法引用调用该方法:
A a = newInstance(A_1::new, x);
当然,反射不是基本情况(但它确实有效)。我提议使用 Factory
来保存所有工厂方法来创建所需的类型。只需在不更改实现的情况下添加新工厂的功能即可。
我提供了一个解决方案而不改变你的主要API public static <T extends Base> T newInstance(Class<T> subType, X x)
.
public class Main {
public static void main(String[] args) throws Exception {
Factory.add(OneBase.class, OneBase::new);
Factory.add(TwoBase.class, TwoBase::new);
OneBase oneBase = Factory.newInstance(OneBase.class, new X());
TwoBase twoBase = Factory.newInstance(TwoBase.class, new X());
}
}
final class Factory {
private static final Map<Class<? extends Base>, Function<X, ? extends Base>> FACTORIES = new HashMap<>();
public static void add(Class<? extends Base> subType, Function<X, ? extends Base> factory) {
FACTORIES.put(subType, factory);
}
public static <T extends Base> T newInstance(Class<T> subType, X x) {
return (T)FACTORIES.get(subType).apply(x);
}
}
final class X {}
abstract class Base {
protected Base(X x) {}
}
final class OneBase extends Base {
public OneBase(X x) {
super(x);
}
}
final class TwoBase extends Base {
public TwoBase(X x) {
super(x);
}
}