I have a class in which i have intialized hashmap in static block. Passing the key, I have retrived the value which is a class. In order to create object for this class. I have used the constructor class to get the constructor and passed arguments and created object.
I have two class in hashmap. To create objectfor EchoExpression I need to pass two arguments and for OutExpression class i need to pass only one argument(String).
Question:
Based on the class returned by the key I need to execute which constructor to get and implement, whether the constructor with one argument or two argument.
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;
}
}
How to choose from the value(class) which class to implement without using if else?
Use an Enum and switch on it. Here is a executable stub without getting too deeply into the reflection or the syntax of your example:
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;
}
}
If you can modify the classes so both constructor has the same signature (accepts the same number/type of arguments in the same order), you could do
Constructor constructor = aClass.getConstructor(new Class[]{String.class,Class.class});
Object object= constructor.newInstance(expression, Boolean.class);
for both classes.
This of course means that the class that right now do not need the extra parameter, will have to ignore the passed-in one it was not using before after the change
UPDATE: Here is a possible way of implementing the idea using Factory classes:
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;
}
}
if
and instanceof
. If you really want to avoid if
, you could use/store factory classes that create the actual objects you want and have a common create method with all the required parameters -- you would essentially end up doing what I suggested above, but with the factory classes instea - Attila 2012-04-04 22:58