Условие выбора метода getConstructor

У меня есть класс, в котором я инициализировал хэш-карту в статическом блоке. Передав ключ, я получил значение, которое является классом. Чтобы создать объект для этого класса. Я использовал класс конструктора, чтобы получить конструктор, передать аргументы и создать объект.

У меня есть два класса в hashmap. Чтобы создать объект для EchoExpression, мне нужно передать два аргумента, а для класса OutExpression мне нужно передать только один аргумент (строка).

Вопрос:

На основе класса, возвращаемого ключом, мне нужно выполнить, какой конструктор получить и реализовать, будь то конструктор с одним аргументом или с двумя аргументами.

public class ExampleFactory {

  private static HashMap<String,Class<?>> hmap = new HashMap<String,Class<?>>();

  static
  {                   
      hmap.put("echo", EchoExpression.class);         
      hmap.put("Out", OutExpression.class);                       
  }

  public void getExpo(String key,String expression)
  {
    Class aClass =map.get(key);

    //Constructor implementation for OutExpression where only one argument string is passed

    Constructor constructor = aClass.getConstructor(new Class[]{String.class});

    Object object= constructor.newInstance(expression);

    //constructor for passing two arguments string for EchoExpression

    Constructor constructor = aClass.getConstructor(new Class[]{String.class,Class.class});

    Object object= constructor.newInstance(expression, Boolean.class);


    return null;        
  }                
}

Как выбрать из значения (класса), какой класс реализовать, не используя if else?


person Jessie    schedule 04.04.2012    source источник


Ответы (2)


Используйте Enum и включите его. Вот исполняемая заглушка, не слишком углубляющаяся в отражение или синтаксис вашего примера:

package com.trip.test;

import java.util.HashMap;
import java.util.Map;

public class ExampleFactory {

    private static Map<String, Class<?>> hmap = new HashMap<String, Class<?>>();

    static {
        hmap.put("echo", EchoExpression.class);
        hmap.put("Out", OutExpression.class);
    }

    public static void getExpo(String key, String expression) {

        Class aClass = hmap.get(key);

        ClassMappingEnum myType = ClassMappingEnum.getClassMappingEnum(aClass);

        switch (myType) {
        case ECHO_EXPRESSION:{
            System.out.println(aClass.getName());
            // do something
            break;
        }
        case OUT_EXPRESSION:{
            System.out.println(aClass.getName());
            // do something
            break;          
        }
        case UNKNOWN:
        default:
            System.out.println("Bummer: " + aClass.getName());          
        }

    }

    public static void main(String[] args) {
        getExpo("echo", "B");
        getExpo("Out", "B");
    }   
}

enum ClassMappingEnum {
    ECHO_EXPRESSION(EchoExpression.class), OUT_EXPRESSION(OutExpression.class), UNKNOWN(null);

    private Class typeDes;

    private ClassMappingEnum(Class typeDes) {
        this.typeDes = typeDes;
    }

    public static ClassMappingEnum getClassMappingEnum(Class compare) {
        for (ClassMappingEnum cme : ClassMappingEnum.values()) {
            if (cme.typeDes.equals(compare)) {
                return cme;
            }
        }
        return UNKNOWN;
    }


}

class EchoExpression<T> {
    private String someString;
    private Class<T> someClass;
    public EchoExpression(String someString, Class<T> someClass) {
        super();
        this.someString = someString;
        this.someClass = someClass;
    }
    public String getSomeString() {
        return someString;
    }
    public void setSomeString(String someString) {
        this.someString = someString;
    }
    public Class<T> getSomeClass() {
        return someClass;
    }
    public void setSomeClass(Class<T> someClass) {
        this.someClass = someClass;
    }


}

class OutExpression {
    private String someString;

    public OutExpression(String someString) {
        super();
        this.someString = someString;
    }

    public String getSomeString() {
        return someString;
    }

    public void setSomeString(String someString) {
        this.someString = someString;
    }

}
person TechTrip    schedule 05.04.2012

Если вы можете изменить классы, чтобы оба конструктора имели одинаковую подпись (принимает одинаковое количество/тип аргументов в том же порядке), вы могли бы сделать

Constructor constructor = aClass.getConstructor(new Class[]{String.class,Class.class});
Object object= constructor.newInstance(expression, Boolean.class);

для обоих классов.

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

ОБНОВЛЕНИЕ: Вот возможный способ реализации идеи с использованием классов Factory:

public interface ObjectFactory
{
  Object create(String expr, Class cls);
}

public class EchoExpressionFactory implements ObjectFactory
{
  public EchoExpression create(String expr, Class cls)
  {
    return new EchoExpression(expr, cls);
  }
}

public class OutExpressionFactory implements ObjectFactory
{
  public OutExpression create(String expr, Class cls)
  {
    return new OutExpression(expr);
  }
}

public class ExampleFactory { 

  private static HashMap<String,ObjectFactory> hmap = new HashMap<String,ObjectFactory>(); 

  static 
  {                    
      hmap.put("echo", new EchoExpressionFactory());          
      hmap.put("Out", new OutExpressionFactory());                        
  } 

  public void getExpo(String key,String expression) 
  { 
    ObjectFactory factory = map.get(key); 

    //Constructor implementation for Expression
    Object object = factory.create(expression); 

    Object object= constructor.newInstance(expression, Boolean.class); 

    return;
  }                 
}
person Attila    schedule 04.04.2012
comment
Я не могу изменить классы, так как это класс файла jar - person Jessie; 05.04.2012
comment
Тогда лучше всего использовать if и instanceof. Если вы действительно хотите избежать if, вы можете использовать/сохранить фабричные классы, которые создают фактические объекты, которые вы хотите, и иметь общий метод создания со всеми необходимыми параметрами - вы, по сути, в конечном итоге сделаете то, что я предложено выше, но вместо этого с фабричными классами - person Attila; 05.04.2012
comment
Кроме того, как насчет принятия одного из ответов на ваш предыдущий вопрос , так как вы в конечном итоге использовали то, что было предложено? - person Attila; 05.04.2012
comment
Спасибо за ваш ответ. Не могли бы вы подробно объяснить мне о фабричном классе, а также об экземпляре. с некоторыми примерами - person Jessie; 05.04.2012