How to determine the type of subclass in a factory template other than using if else and switch?

I wanted to try the factory pattern and was able to implement it, but when generating for more than a few classes, I thought it would be ugly !! therefore any clarity or suggestions would be truly appreciated ...

My superclass:

public abstract class Output { public abstract void generate(Data dat); } 

I got other classes coming out of Output, like

 public class generateXML extends Output{ . . . } 

My question is related here:

 public class generatorFactory(){ public Output generate(String str){ 

// or get the object as an argument of type (Object obj)

 if(str.equals("xml"){ return new generateXML(); } else if......... ...... } 

Is there any way to determine the type of a subclass, avoiding checking for each type?

+4
source share
5 answers

You can use newInstance () to initialize the generator whose class name you built from the parameter:

 public Generator getGenerator (final String type) { final Class generatorClass = ClassLoader.getSystemClassLoader().loadClass("Generator"+type); final Generator generator = (Generator) (generatorClass.newInstance()); return generator; } 

PS: I appreciate that you follow the rules of Java: if generateXML is a class, it should be written by GenerateXML.

Moreover: be careful when naming your classes. (1) The generateXML shouln'd object extends Output because it is not an output. (2) "GenerateXML" is a verb, i.e. Act. Therefore, this is not the right word for an object, but a method. You can name the object in the example "XMLGenerator".

+1
source

You should consider replacing your if-else chain with a card.

Instead of writing code that checks all the lines that you want to maintain, you only have a canopy of lines to extract the item from the map.

Of course, you will need one more configuration code to place elements on the map, but this should be trivial.

Here is a good article about this topic (in PHP)

+2
source

You can use enum , which you can pass to factory and return a factory object based on the enumeration passed. The only thing you can not export as an API.

  enum Type { XML { @Override public Object getFactory() { // TODO Auto-generated method stub return null; } }; public abstract Object getFactory(); } 

If you need to expose it as an API, you can do something like below.

 interface IType { public abstract Object getTypeFactory(); } enum Type implements IType { XML { @Override public Object getTypeFactory() { // TODO Auto-generated method stub return null; } }; } 

And replace the factory method with

 public static Object getFactoryByType(String name) { Type type = Type.valueOf(name); return type.getTypeFactory(); } 
+1
source

You can use Reflection.

 Object generated = getClass().getMethod("generate" + type.toUpperCase()).invoke(this); public Object generateXML(); public Object generateJSON(); public Object generateCSV(); 
+1
source

Since you should call new each time, I'm not sure if you can get around the branching process. Someone should know what to return.

If for single games you could initialize the HashMap "xml"=>generateXML singleton

After the second, you can change your String attribute for differents Type classes MyTypeXML, MyTypeJSON, ... and then use the method with the same name but with a different type.

 public Output generate(MyTypeXML xml) { // This will go for XML } public Output generate(MyTypeJSON json) { // This will go for JSON } 

But for factories, I really don't mind coding if ... else.

0
source

Source: https://habr.com/ru/post/1432213/


All Articles