2015-06-18 9 views
1

Мой класс, как это:Java способ создания объекта на основе перечислимого типа

class X {} 
class Y extends X {}; 
class Z extends X {}; 

У меня есть перечисление для каждого подкласса (ид + класс):

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(); 
    } 
} 

Тогда я использовал их следующим образом:

X parseFromID(int id) { 
    for (Type v : Type.values()) { 
    if (v.id == id) { 
     return v.createInstance(); 
    } 
    } 
} 

Он отлично работает, но мне интересно, если это Java-IST способ создания данных на основе целого идентификатора? Есть ли что-то плохое, что нужно искать?

Есть ли способ принудительного применения класса, который передается, имеет тип X без длительного условия if-else? Подумайте, когда у меня есть большое количество подклассов.


Почему вы хотите работать на целочисленных идентификаторов?

Я пишу какой-то синтаксический анализатор, поэтому мне нужно преобразовать целочисленный идентификатор, который я взял где-то в соответствующий объект.

ответ

5

На самом деле нет смысла использовать отражение здесь. Бросание Исключение - также плохая практика, и если вы не использовали рефлексию, вам не пришлось бы иметь дело с исключениями отражения. Вы можете просто сделать

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(); 
} 

Это также полезно, потому что оно не заставит каждый подкласс иметь публичный конструктор без аргументов, а также позволяет вернуться один и тот же экземпляр X или Y, если это возможно.

Если вы обеспокоены многословие определений анонимного класса, вы могли бы заменить их лямбды, если вы используете Java 8:

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(); 
    } 
} 
+0

Я думаю об этом, но он собирается стать очень длинный код, очень скоро, если у меня есть большое количество подклассов правых? – w00d

+0

Это немного многословие, но не так долго. См. Мой отредактированный ответ для менее подробного решения. –

+0

Вторая версия не очень отличается от моей, в чем основное преимущество? – w00d

0

Есть ли способ обеспечить класс который передается в X-тип без длительного условия if-else?

Да, вы можете использовать generics для ограничения класса. Измените конструктор на:

public Type(int id, Class<? extends X> c) { this.id = id; this.c = c; } 

Почему вы хотите работать с целыми идентификаторами? Вы можете использовать либо значения перечисления напрямую, либо - если вам нужно их перенести или сохранить - их строковое представление и, если необходимо, проанализировать строку, используя метод ente valueOf.

1

Используя фабрику и карту более академический:

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(); 
    } 
}