Better way to instantiate multiple different classes in Java via factories - java

Say you have a lot of similar classes that may get instantiated at any point. One obvious way to write this would be a whole slew of conditionals:
public static Common factory(String key, InstantiationObj instantiationObj) {
if( key == "A") {
return new TypeA(instantiationObj);
}
else if( key == "B") {
return new TypeB(instantiationObj);
}
else if( key == "C" ) {
return new TypeC(instantiationObj);
}
else if( key == "D" ) {
return new TypeD(instantiationObj);
}
else {
return new DefaultClass(instantiationObj);
}
}
I like to avoid all the conditionals though. In Java I got this working:
public static <T extends Common> T factory(String key, InstantiationObj instantiationObj) throws Exception {
Class[] cArg = new Class[1];
cArg[0] = InstantiationObj.class;
HashMap<String, Class> potentialClasses = new HashMap<>();
potentialClasses.put("A", TypeA.class);
potentialClasses.put("B", TypeB.class);
potentialClasses.put("C", TypeC.class);
potentialClasses.put("D", TypeD.class);
Class<T> classType = potentialClasses.getOrDefault(key, DefaultClass.class);
return classType.getDeclaredConstructor(cArg).newInstance(instantiationObj);
}
This is much easier to test, but it still looks clunky to me especially the block to determine the right constructor. Does Java have a more streamlined way of executing this pattern?

One suggestion can be
public class CommonClass {
private static HashMap<String, Class> potentialClasses = new HashMap<>();
static {
potentialClasses.put("A", TypeA.class);
potentialClasses.put("B", TypeB.class);
potentialClasses.put("C", TypeC.class);
potentialClasses.put("D", TypeD.class);
}
public static <T extends Common> T factory(String key) throws Exception {
Class[] cArg = new Class[1];
cArg[0] = NecessaryConstructor.class;
Class<T> classType = potentialClasses.getOrDefault(key, DefaultClass.class);
return classType.getDeclaredConstructor(cArg).newInstance(descriptor);
}

In case the logic is so simple as in your case, you may use reflection, without defining mapping:
public static Common factory(String key, InstantiationObj instantiationObj) {
String className = "Type" + key;
Class<T> classType = Class.forName(className);
...
Thus, for key "A" the variable className will have value "TypeA", for key "B" it will have value "TypeB", etc.
But this will work in this simple case only, when mapping of parameter key to class names follows a simple pattern.
In case the logic becomes more complex later on, you would need if (...) clauses for every condition.

One way I like implementing the factory pattern is with using spring. You can have as many classes of a specific type in your project.
Then, inject or autowire a List of same type in a class and Spring will set all instances of that type in the list.
Finally, transform the list to a map like you have and you will have maximized the idea of
“Closed for modification , open for extensibility” on you factory and project.

Related

Use enum to create thead-safe factory instances

I write the code for creating multiple instances for the thread-safe factory creation:
public class XWebserviceObjectFactoryCreator {
}
However, the code looks repeating to me and not happy about it. Is it possible to use enum (or something else) to make it more readable?
Since the example shows all the classes have no-argument constructors, you can use the Class.newInstance method, so something like :
private static Map<Class<?>, Object> instances = new HashMap<>();
public static <T extends Object> T getObjectFactoryInstance(Class<T> clazz) {
Object result;
if ((result = instances.get(clazz)) == null) {
synchronized (instances) {
if ((result = instances.get(clazz)) == null) {
try {
result = clazz.newInstance();
instances.put(clazz, result)
} catch (InstantiationException | IllegalAccessException e) {
// do something
}
}
}
}
return (T)result;
}
Apologies if layout or syntax is off, but I’m away from my computer and doing this on the phone - but hope you get the idea !
If any classes do require arguments in their constructors, then you’ll have to use reflection to invoke the constructor.
Finally, note that I’ve modified the declaration of clazz from Class<?> to Class< T>, to let the generics validate the caller by tying the output to the given Class.
you can use the Abstract Factory design Pattern along with Enum where Sales2ObjectFactory, OrderingObjectFactory, Settings2ObjectFactory, and SettingsObjectFactory can be a factory in itself with a common interface.
Then you can use Enum to get the instance of one of those factories.
public static class FactoryMaker {
public enum FactoryType {
SALES2OBJECT, ORDERING,SETTING2OBJECT,SETTINGS
}
public static CommonFactory makeFactory(FactoryType type) {
switch (type) {
case SALES2OBJECT:
return new Sales2ObjectFactory();
case ORDERING:
return new OrderingObjectFactory();
case SETTING2OBJECT:
return new Settings2ObjectFactory();
case SETTINGS:
return new new SettingsObjectFactory();
default:
throw new IllegalArgumentException("FactoryType not supported.");
}
}
}
Please check :: https://java-design-patterns.com/patterns/abstract-factory/

Impact of multiple threads using same object in a singleton class

I'm designing a module which can support different datasources.
My module gets the user's company id as inputs and I must call the appropriate class based on the company id.
I'm trying to incorporate some good design and avoid conditional statements where possible.
I have a FetchDataSource singleton class with this method.
public class FetchDataSourceSingleton {
private static Map<String, Communicator> communicatorMap;
public static Communicator getCommunicatorInstance(String dataSourceType) {
if (communicatorMap == null || communicatorMap.isEmpty())
populateCommunicatorMap();
if (communicatorMap.containsKey(dataSourceType))
return communicatorMap.get(dataSourceType);
return null;
}
.... other methods including populateCommunicatorMap()
}
"Communicator" is an interface, and the communicator map will return the appropriate instance.
This is the populateCommunicatorMap() method in the same singleton class.
private static void populateCommunicatorMap() {
communicatorMap = new HashMap<String, Communicator>();
communicatorMap.put("AD", new ADCommunicator());
communicatorMap.put("DB2", new DB2Communicator());
communicatorMap.put("MYSQL", new MYSQLCommunicator());
}
ADCommunicator, DB2Communicator and MYSQLCommunicator will implement the Communicator inteface.
The code seems to work in my test draft.
The only concern I have is the HashMap will return the same object for all communication requests to the same type. I can't seem to avoid having the same instance in the hashmap if I want to avoid the conditional statements. Otherwise instead of the hashmap, I could have just make calls like this.
Communicator comm;
if (type = "AD") comm = new ADCommunicator();
if (type = "DB2") comm = new DB2Communicator();
if (type = "MYSQL") comm = new MYSQLCommunicator();
I've avoided this by using the hashmap to return an instance based on type.
But then I can't avoid the singleton problem where I get the same instance.
In a multithreaded environment, which needs to support hundreds of thousands of communication requests at a time, this could be a problem considering I'll need to syncronize a lot of code in each of the Communicator classes.
Is there a way I can avoid the syncronization and make it thread safe without impacting performance?
I can't seem to avoid having the same instance in the hashmap
You can use a switch instead of a bunch of ifs.
Switch Over an enum (Java 5)
Change type to be an enum in Java 5+, then you can switch on it. I'd recommend enums in general for type safety.
// type is-a enum Communicator.TYPE
switch(type) {
case AD: return new ADCommunicator();
case DB2: return new DB2Communicator();
case MYSQL: return new MYSQLCommunicator();
default: return null;
}
Switch over a String (Java 8)
Java 8 can switch over Strings directly.
// type is-a String
switch(type) {
case "AD": return new ADCommunicator();
case "DB2": return new DB2Communicator();
case "MYSQL": return new MYSQLCommunicator();
default: return null;
}
Switching over an enum will be as fast as a map, if not faster. Switching on the string will be as fast as a Map.
A Map of Factory (factory of factories)
Or have a map of factories:
private final static Map<String, Factory<? extends Communicator>> map;
static {
map.put("AD", ADCommunicatorFactory.getInstance());
//...
map.put(null, NullFactory<Communicator>.getInstance());
} // populated on class-load. Eliminates race from lazy init
// on get
return map.get(type).make();
A Map of Class (reflection)
Or use the reflection API to make instances, but then it would probably be better to just use conditionals.
// on init
Map<String, Class<? extends Communicator>> map = new HashMap<>();
map.put("AD", ADCommunicator.class);
// on get
try {
return (Communicator) map.get(type).newInstance();
} catch(InstantiationException | IllegalAccessException | NullPointerException e) {
return null;
}
P.S.
This all sounds like premature optimization. I doubt that determining which Communicator to use is going to be a bottleneck in your system.
If all your communicators can be constructed with empty argument list constructor, then you can store the type (class) of the communicator in the map instead of an instance. Then you can look up the type (java.lang.Class) from your communicatorMap and instantiate a new instance with java.lang.Class.newInstance().
For example:
public interface Communicator {
void communicate();
}
public class Communicator1 implements Communicator {
public void communicate() {
System.out.println("communicator1 communicates");
}
}
public class Communicator2 implements Communicator {
public void communicate() {
System.out.println("communicator2 communicates");
}
}
public class CommuniicatorTest {
public static void main(String[] args) throws Exception {
Map<String, Class<? extends Communicator>> communicators = new HashMap<String, Class<? extends Communicator>>();
communicators.put("Comm1", Communicator1.class);
communicators.put("Comm2", Communicator2.class);
Communicator comm2 = communicators.get("Comm2").newInstance();
comm2.communicate();
System.out.println("comm2: " + comm2);
Communicator anotherComm2 = communicators.get("Comm2").newInstance();
anotherComm2.communicate();
System.out.println("anotherComm2: " + anotherComm2);
}
}
result:
communicator2 communicates
comm2: pack.Communicator2#6bc7c054
communicator2 communicates
anotherComm2: pack.Communicator2#232204a1
Assylias is correct about using a static initializer. It runs when your class loads, which guarantees that the map will be loaded before anything else happens to the class.
You didn't show the declaration of the map; I assume that it is static.
private final static Map<String, Communicator> communicatorMap;
static {
communicatorMap = new HashMap<>();
communicatorMap.put("AD", new ADCommunicator());
communicatorMap.put("DB2", new DB2Communicator());
communicatorMap.put("MYSQL", new MYSQLCommunicator());
}; // populated on class-load. Eliminates race from lazy init
The remaining issue is the Communicator implementation. All this assumes that it is thread-safe as well.

Generic type invocation using string class names

Hope you can help me with this:
I have ...
a string list of class names called classNameList
a generic class Geography<T>
a static generic method <T> void read(Class<T> cl, Geography<T> geo)
I want to loop through the string class name list and call the generic method for each of these classes.
What I tried but obviously did not work:
for (int i = 0; i < classNameList.length; i++) {
Class<?> myClass = Class.forName(classNameList[i].getName());
Geography<myClass.newInstance()> geo;
read(myClass, geo);
}
Error: myClass.newInstance cannot be resolved to a type
My code runs perfectly for a single call of the generic function:
Geography<ExampleClass> ExampleGeo;
read(ExampleClass.class, ExampleGeo);
Any ideas how I could do this?
UPDATE:
Thanks for the helpful input, still it's hard for me to adopt it to my real code.
So this is the non simplyfied problem:
I do ready in shapefile-Data with a shapefileLoader, for each feature of the Shapefile a class (GuadAgent) is initialized with a predifined class (PlantWind). I have shapefiles in my input-directory with the names of the Classes their features do represent. I want Java to read in the shapefiles and create the respective agent class. (the agents are also placed in a context and a geography..)
Used classes are: ShapefileLoader, Geography, the other classes can be find at the same website
This part is in the main-method:
Geography<GuadAgent> guadGeography = GeographyFactoryFinder.createGeographyFactory(null).createGeography("guadGeography", context, new GeographyParameters<GuadAgent>());
Context<GuadAgent> context = new DefaultContext<GuadAgent>();
FileFilter filter = new FileFilter() {
#Override
public boolean accept(File file) {
return file.getName().endsWith(".shp"); // return .shp files
}
};
String shapefileDir = System.getProperty("user.dir")+"\\input\\shp\\";
File folder = new File(shapefileDir);
File[] listOfFiles = folder.listFiles(filter);
for (File classFile : listOfFiles) {
try {
readForName(classFile,context,guadGeography);
} catch (ClassNotFoundException | MalformedURLException
| FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The static Method that reads in the names:
static <T> void readForName(File classFile, Context<GuadAgent> context,Geography<GuadAgent> guadGeography) throws ClassNotFoundException, MalformedURLException, FileNotFoundException {
String shapefileDir = System.getProperty("user.dir")+"\\input\\shp\\";
String className = classFile.getName().split("\\.(?=[^\\.]+$)")[0];
File shapefile = null;
shapefile = new File(shapefileDir+classFile.getName());
if (!shapefile.exists()) {
throw new FileNotFoundException("Could not find the given shapefile: " + shapefile.getAbsolutePath());
}
switch (className) {
case "PlantWind":
ShapefileLoader<PlantWind> PlantWindLoader = new ShapefileLoader<PlantWind>(PlantWind.class,shapefile.toURI().toURL() , guadGeography, context);
PlantWindLoader.load();
PlantWindLoader.close();
System.out.println(context.getObjects(PlantWind.class).size());
break;
// Todo Add other Agent types
default:
break;
}
How can I get rid of the switch? Although their number is finit, there are very many different agents...
Unfortunately, there's no syntax close to your intention (nice idea though).
The basic problem is that Class.forName() returns an unknown Class<?>, so you need a cast somewhere. It's just a mater of where you put it.
I suggest this approach (which compiles) that bundles up doing a read() based on a class name:
static <T> void readForName(String className) throws ClassNotFoundException {
Class<T> myClass = (Class<T>) Class.forName(className);
Geography<T> geo = new Geography<T>(); // No code shown. Adjust as required
read(myClass, geo);
}
May I also suggest using the foreach loop syntax, for tidier code:
for (String className : classNameList) {
readForName(className.getName());
}
Creating instances from Generic Types at Runtime
I am not entirely clear on what you are trying to accomplish, but at first look it looks like the simplest solution is the best solution.
It could be solved with using a scripting environment ( Groovy, JavaScript, JRuby, Jython ) that could dynamically evaluate and execute arbitrary code to create the objects, but that got extremely convoluted and overly complex, just to create an object.
But unfortunately I think it has a very pedestrian solution.
As long as there is a predefined set of supported types, you can use a Factory pattern. Here I just leverage the Provider<>T interface from the javax.inject/com.google.inject package.
Q26289147_ProviderPattern.java
public class Q26289147_ProviderPattern
{
private static final List<String> CLASS_NAMES = ImmutableList.of("String", "Integer", "Boolean");
private static final Map<String, Provider<StrawManParameterizedClass>> PROVIDERS;
static
{
final ImmutableMap.Builder<String, Provider<StrawManParameterizedClass>> imb = ImmutableMap.builder();
for (final String cn : CLASS_NAMES)
{
switch (cn)
{
case "String":
imb.put(cn, new Provider<StrawManParameterizedClass>()
{
#Override
public StrawManParameterizedClass<String> get() { return new StrawManParameterizedClass<String>() {}; }
});
break;
case "Integer":
imb.put(cn, new Provider<StrawManParameterizedClass>()
{
#Override
public StrawManParameterizedClass<Integer> get() { return new StrawManParameterizedClass<Integer>() {}; }
});
break;
case "Boolean":
imb.put(cn, new Provider<StrawManParameterizedClass>()
{
#Override
public StrawManParameterizedClass<Integer> get() { return new StrawManParameterizedClass<Integer>() {}; }
});
break;
default:
throw new IllegalArgumentException(String.format("%s is not a supported type %s", cn, Joiner.on(",").join(CLASS_NAMES)));
}
}
PROVIDERS = imb.build();
}
static <T> void read(#Nonnull final StrawManParameterizedClass<T> smpc) { System.out.println(smpc.type.toString()); }
static abstract class StrawManParameterizedClass<T>
{
final TypeToken<T> type = new TypeToken<T>(getClass()) {};
#Override
public String toString() { return type.getRawType().getCanonicalName(); }
}
public static void main(final String[] args)
{
for (final String cn : CLASS_NAMES)
{
read(PROVIDERS.get(cn).get());
}
}
}
Disclaimer:
This is just a proof of concept example, I would never use a switch
statement like that in production code I would use a Strategy
Pattern or Chain of Responsibility Pattern to encapsulate the logic
of what type to create based on the ClassName key.
This initially looked like a generics problem, it isn't, it is a creation problem.
That said, you don't need to pass around instances of Class<?> you can get Generic Type information off of Parameterized classes at runtime with TypeToken from Guava.
You can even create instances of any generic type at runtime with TypeToken from the Guava library.
The main problem is this syntax isn't supported: Geography<myClass.newInstance()> geo; and I can't think of anyway to fake it other than the Provider implementation above.
Here is a straw man example of how to use TypeToken so that your
parameterized classes will always know their types!
Q26289147.java
import com.google.common.reflect.TypeToken;
public class Q26289147
{
public static void main(final String[] args) throws IllegalAccessException, InstantiationException
{
final StrawManParameterizedClass<String> smpc = new StrawManParameterizedClass<String>() {};
final String string = (String) smpc.type.getRawType().newInstance();
System.out.format("string = \"%s\"",string);
}
static abstract class StrawManParameterizedClass<T>
{
final TypeToken<T> type = new TypeToken<T>(getClass()) {};
}
}
Notes:
Works great for classes that have a default no arg constructor.
Works better than using straight reflection if there are no default no arg constructors.
Should play well with Guice allowing you to use the ".getRawType()generatedClassto pass togetInstance()` of an Injector. have not tried this yet, I just thought of it!
You can use Class<T>.cast() to do casting that doesn't need #SuppressWarning("unchecked") all over the place.`
You can create a static factory method in Geography (or in any other class):
public static <T> Geography<T> newInstance(Class<T> cls)
throws ReflectiveOperationException {
return new Geography<T>(cls.newInstance());
}
I made a guess at the Geography class's constructor. If I guessed wrong, edit your question to include the constructor(s) in Geography.
You can create a static factory method in Geography (or in any other class):
public static <T> Geography<T> newInstance(Class<T> cls)
throws ReflectiveOperationException {
return new Geography<T>(cls.newInstance());
}
I made a guess at the Geography class's constructor. If I guessed wrong, edit your question to include the constructor(s) in Geography.
Update: I'm not sure what the Geography class is meant to do. If it needs a generically typed object, it might look like this:
public class Geography<T> {
private final T data;
public Geography(T data) {
this.data = Objects.requireNonNull(data);
}
}
If it needs a class, the constructor might look like this:
public class Geography<T> {
private final Class<T> dataClass;
public Geography(Class<T> cls) {
this.dataClass = Objects.requireNonNull(cls);
}
}

Anything wrong with instanceof checks here?

With the introduction of generics, I am reluctant to perform instanceof or casting as much as possible. But I don't see a way around it in this scenario:
for (CacheableObject<ICacheable> cacheableObject : cacheableObjects) {
ICacheable iCacheable = cacheableObject.getObject();
if (iCacheable instanceof MyObject) {
MyObject myObject = (MyObject) iCacheable;
myObjects.put(myObject.getKey(), myObject);
} else if (iCacheable instanceof OtherObject) {
OtherObject otherObject = (OtherObject) iCacheable;
otherObjects.put(otherObject.getKey(), otherObject);
}
}
In the above code, I know that my ICacheables should only ever be instances of MyObject, or OtherObject, and depending on this I want to put them into 2 separate maps and then perform some processing further down.
I'd be interested if there is another way to do this without my instanceof check.
Thanks
You could use double invocation. No promises it's a better solution, but it's an alternative.
Code Example
import java.util.HashMap;
public class Example {
public static void main(String[] argv) {
Example ex = new Example();
ICacheable[] cacheableObjects = new ICacheable[]{new MyObject(), new OtherObject()};
for (ICacheable iCacheable : cacheableObjects) {
// depending on whether the object is a MyObject or an OtherObject,
// the .put(Example) method will double dispatch to either
// the put(MyObject) or put(OtherObject) method, below
iCacheable.put(ex);
}
System.out.println("myObjects: "+ex.myObjects.size());
System.out.println("otherObjects: "+ex.otherObjects.size());
}
private HashMap<String, MyObject> myObjects = new HashMap<String, MyObject>();
private HashMap<String, OtherObject> otherObjects = new HashMap<String, OtherObject>();
public Example() {
}
public void put(MyObject myObject) {
myObjects.put(myObject.getKey(), myObject);
}
public void put(OtherObject otherObject) {
otherObjects.put(otherObject.getKey(), otherObject);
}
}
interface ICacheable {
public String getKey();
public void put(Example ex);
}
class MyObject implements ICacheable {
public String getKey() {
return "MyObject"+this.hashCode();
}
public void put(Example ex) {
ex.put(this);
}
}
class OtherObject implements ICacheable {
public String getKey() {
return "OtherObject"+this.hashCode();
}
public void put(Example ex) {
ex.put(this);
}
}
The idea here is that - instead of casting or using instanceof - you call the iCacheable object's .put(...) method which passes itself back to the Example object's overloaded methods. Which method is called depends on the type of that object.
See also the Visitor pattern. My code example smells because the ICacheable.put(...) method is incohesive - but using the interfaces defined in the Visitor pattern can clean up that smell.
Why can't I just call this.put(iCacheable) from the Example class?
In Java, overriding is always bound at runtime, but overloading is a little more complicated: dynamic dispatching means that the implementation of a method will be chosen at runtime, but the method's signature is nonetheless determined at compile time. (Check out the Java Language Specification, Chapter 8.4.9 for more info, and also check out the puzzler "Making a Hash of It" on page 137 of the book Java Puzzlers.)
Is there no way to combine the cached objects in each map into one map? Their keys could keep them separated so you could store them in one map. If you can't do that then you could have a
Map<Class,Map<Key,ICacheable>>
then do this:
Map<Class,Map<Key,ICacheable>> cache = ...;
public void cache( ICacheable cacheable ) {
if( cache.containsKey( cacheable.getClass() ) {
cache.put( cacheable.getClass(), new Map<Key,ICacheable>() );
}
cache.get(cacheable.getClass()).put( cacheable.getKey(), cacheable );
}
You can do the following:
Add a method to your ICachableInterface interface that will handle placing the object into one of two Maps, given as arguments to the method.
Implement this method in each of your two implementing classes, having each class decide which Map to put itself in.
Remove the instanceof checks in your for loop, and replace the put method with a call to the new method defined in step 1.
This is not a good design, however, because if you ever have another class that implements this interface, and a third map, then you'll need to pass another Map to your new method.

Create different objects depending on type

I have a database table that contains a column named type. For every row in my database column I have to create an object depending on the type. At the moment I use if else statements for that:
if (type.equals("object1")){
Object1 object1 = new Object1();
}
else if (type.equals("object2")){
Object2 object2 = new Object2();
}
Somewhat nicer would be to use an enum, as the number of types is limited but is there a possibility to let the creation of an object depend on the value of the String?
I'm open to suggestions that might solve my problem in another way than I am trying to.
You could create a map from String to Class and use newInstance. That however relies on the existence of no-arg constructors.
import java.util.*;
class Test {
public static void main(String[] args) throws Exception {
Map<String, Class<?>> classes = new HashMap<String, Class<?>>();
classes.put("object1", Object1.class);
classes.put("object2", Object2.class);
String type = "object2";
Object obj = classes.get(type).newInstance();
//...
}
}
class Object1 { ... }
class Object2 { ... }
You can use
Object o = Class.forName(type).newInstance();
If you have an int and two Strings as arguments you need.
Object o = Class.forName(type)
.getConstructor(int.class, String.class, String.class)
.newInstance(intValue, string1, string2);
Another possibility is to use factory methods
Object o = getClass().getMethod("create_" + type).invoke(null);
static Object1 create_object1() {
return new Object1(/* with args */);
}
static Object2 create_object2() {
return new Object2(/* with other args */);
}
but the most flexible approach may be to use a switch
Object o;
switch(type) { // in Java 7
case "object1": o = new Object1(); break;
case "object2": o = new Object2(); break;
What would be more elegant is using closures in Java 8.
http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html
package main;
import java.util.ArrayList;
import java.util.List;
public class TempClass {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
List<Class> classes = new ArrayList<Class>() {{
add(Class.forName("main.Object1"));
add(Class.forName("main.Object2"));
}};
for (Class aClass : classes) {
Object o = aClass.newInstance();
}
}
}
package main;
public class Object1 {
public Object1() {
System.out.println("Object1");
}
}
package main;
public class Object2 {
public Object2() {
System.out.println("Object2");
}
}
If the classes in question are part of an inheritance hierarchy and you happen to use some kind of mapping tool/framework like Hibernate or iBATIS/MyBatis, it might include a way to configure so called discriminators.
You could then configure your "type" column as the descriminator column and map the supported values to your classes. The framework will then instantiate the appropriate classes for you when you retrieve the objects from the database.
Using switch or if statements forces you to hard-code the various options, so you will obtain a not so flexible solution, in my opinion.
I always prefer to write code that is extensible for future software developments.
So I suggest you to use Object o = Class.forName(type).newInstance(); putting in your database the name of the class you want to instantiate and, if you need it, a custom label.
EDIT
If you have to pass some parameter to the constructors of the classes you have to instantiate, is convenient to use Constructor.newInstance() instead of Class.newInstance(); and use the Constructor object to instantiate the class, for example:
Class myClass = Class.forName(type);
// get the constructor you need specifying parameters type
Constructor constructor = myClass.getConstructor(String.class);
Object myObject = constructor.newInstance("constructor-arg");

Categories

Resources