Am I abusing / abusing Java reflection?

I am writing a program to read data from a file, which can be in one of several formats (in fact, these are different versions of the same format), and I use reflection to call the corresponding function for each format. Assuming the file format is the number indicated in the first byte of the file:

Class DataFile extends Model { ... Blob file ... public void parse() throws Exception{ InputStream is = file.get(); Class c = Class.forName("models.DataFile"); Method m = c.getMethod("parse_v"+is.read(), (Class []) null); m.invoke(this, (Object []) null); } public void parse_v0() throws Exception{ ... } public void parse_v1() throws Exception{ ... } } 

My question is: do I abuse / abuse thoughts? I have the feeling that I have to use inheritance and create another class for each file type with its own “parsing” procedure, but I don’t know the file type until I start parsing ... and then I can’t “lower” it , and just use something like ((DataFile_v1) this).parse() , so I lost a bit.

Thank you for your time!

+6
source share
5 answers

There is nothing fundamentally wrong with this, but a more flexible and extensible way to do the same would be to use version information as a key in Map , and values ​​in Map be handler objects. Then any code can register a handler (all handlers can implement a common interface ), and your reader code can simply find the handler in Map and call it.

Be sure to handle the case when Map does not contain a handler for a specific version!

+7
source

If you create a DataFile interface, define a parse method, and implement an interface with several classes ( DataFile_v1 , etc.), then the calling code does not need to know which implementation has been selected.

 DataFile dataFile = dataFileFactory.getForVersion(is.read()); dataFile.parse(file); 

I would say that this is the best approach in terms of overall design. However, at some point you will need to create some sort of mapping between the version number and the DataFile implementations. (In this case, I am doing this in an imaginary dataFileFactory .) You will need to determine if it would be more appropriate to choose an implementation using reflection or some other method.

+2
source

I think it's good to use reflection here. An alternative would be to use inheritance or enumeration (i.e. a strategy template ) and map from the version code to the corresponding strategy. After you initialize all the necessary mappings, you simply get the desired parser object from the map and call it. However, to configure this solution, a significant amount of template code is still required, which reduces its readability.

0
source

What you do is not bad. If you want to have different parsers in different classes, you cannot omit as you say, but you can create an instance of a new parser object. This way, your existing class will be a facade in front of the actual parsers that are not created until you know which format you are parsing.

0
source

You can use a collection, but using reflections also looks for a collection. If your display does not change, I would use reflections.

 getClass().getMethod("parse_v"+is.read()).invoke(this); 
0
source

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


All Articles