[英]Java way to create an object based on enum type
My class is like this: 我的课是这样的:
class X {}
class Y extends X {};
class Z extends X {};
I have an enum for each subclass (id + class): 我为每个子类(id +类)都有一个枚举:
enum Type {
Y_TYPE(1, Y.class), Z_TYPE(2, Z.class);
int id;
Class c;
public Type(int id, Class c) { this.id = id; this.c = c; }
public static X createInstance() throws Exception {
return c.newInstance();
}
}
Then I used them as follows: 然后我按如下方式使用它们:
X parseFromID(int id) {
for (Type v : Type.values()) {
if (v.id == id) {
return v.createInstance();
}
}
}
It works fine but I'm wondering if this a Java-ist way to create data based on integer id ? 它工作正常,但我想知道这是一种基于Java的方法来基于整数id创建数据吗? Is there any bad thing that should look for ?
有什么不好的事情应该寻找吗?
Is there a way to enforce the class that is passed into are of X type without lengthy if-else condition? 有没有一种方法可以强制传入X类型的类而无需冗长的if-else条件? Think when I have a large number of subclasses.
想一想当我有大量的子类时。
Why do you want to work on integer ids?
为什么要使用整数ID?
I'm writing some sort of parser, so I need to convert integer id that I've taken from somewhere to the appropriate object. 我正在编写某种解析器,因此需要将我从某处获取的整数id转换为适当的对象。
There is really no reason to use reflection here. 确实没有理由在这里使用反射。 Throwing Exception is also a bad practice, and if you didn't use reflection, you wouldn't have to deal with reflection exceptions.
抛出异常也是一种不好的做法,并且如果您不使用反射,则不必处理反射异常。 You could simply do
你可以做
enum Type {
Y_TYPE(1) {
@Override
public X createInstance() {
return new Y();
}
}, Z_TYPE(2) {
@Override
public X createInstance() {
return new Z();
}
};
private int id;
private Type(int id) {
this.id = id;
}
public abstract X createInstance();
}
This is also helpful because it doesn't force every subclass to have a public no-arg constructor, and also allows returning the same instance of X or Y, if possible. 这也很有帮助,因为它不会强制每个子类都具有公共的无参数构造函数,并且如果可能的话,还允许返回相同的X或Y实例。
If you're concerned about the verbosity of the anonymous class definitions, you could replace them with lambdas, if you're using Java 8: 如果您担心匿名类定义的冗长性,那么如果使用的是Java 8,则可以用lambda替换它们:
import java.util.function.Supplier;
enum Type {
Y_TYPE(1, X::new), Z_TYPE(2, Y::new);
private int id;
private Supplier<X> supplier;
private Type(int id, Supplier<X> supplier) {
this.id = id;
this.supplier = supplier;
}
public X createInstance() {
return supplier.get();
}
}
Using a factory and a map is more academic: 使用工厂和地图更具学术性:
import java.util.HashMap;
import java.util.Map;
interface Factory<T> {
T createInstance();
}
class X {/**/}
class Y extends X {/**/}
class Z extends X {/**/}
class Factories {
static Map<Integer, Factory<?>> factories = new HashMap<>();
static {
factories.put( 1, X::new );
factories.put( 2, Y::new );
factories.put( 3, Z::new );
}
@SuppressWarnings("unchecked")
static <T> Factory<T> get( int id ) {
return (Factory<T>)factories.get( id );
}
}
public class Main {
static void main( String[] args ) {
final Factory<X> fx = Factories.get( 1 );
final X x = fx.createInstance();
final Factory<Y> fy = Factories.get( 2 );
final Y y = fy.createInstance();
final Factory<Z> fz = Factories.get( 3 );
final Z z = fz.createInstance();
}
}
Is there a way to enforce the class that is passed into are of X type without lengthy if-else condition?
有没有一种方法可以强制传入X类型的类而无需冗长的if-else条件?
Yes, you can use generics to restrict the class. 是的,您可以使用泛型来限制类。 Change the constructor to:
将构造函数更改为:
public Type(int id, Class<? extends X> c) { this.id = id; this.c = c; }
Why do you want to work on integer ids? 为什么要使用整数ID? You can use either the enum values directly or - if you need to transfer or store them - their string representation and parse the String if needed using the enum's
valueOf
method. 您可以直接使用枚举值,也可以(如果需要传输或存储它们)使用它们的字符串表示形式,并在需要时使用枚举的
valueOf
方法解析String。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.