I am building a piece of software that sends and receives messages in particular binary definitions and with a particular version. As such, I have classes that look like this, which vary mostly only in the package name (the version, in this case):
For version 1.5:
com.mydomain.clothesmessage.v0105.fielddefinitions.Field100
com.mydomain.clothesmessage.v0105.fielddefinitions.Field200
com.mydomain.clothesmessage.v0105.messagedefinitions.Pants
com.mydomain.clothesmessage.v0105.messagedefinitions.Socks
and for version 2.7:
com.mydomain.clothesmessage.v0207.fielddefinitions.Field100
com.mydomain.clothesmessage.v0207.fielddefinitions.Field200
com.mydomain.clothesmessage.v0207.messagedefinitions.Pants
com.mydomain.clothesmessage.v0207.messagedefinitions.Socks
The class that manages the transmission and reception of these messages uses all versions, depending on where the message comes from, etc.
My problem is that defining an instance of the class requires I use the entire package path, because otherwise it's ambiguous. Even if there exists a situation where I use only one version in a given file, a casual reader of the code won't be able to see what version is being used. Pants pants = new Pants()
is ambiguous until you look at the imported package.
My ideal usage of this would be something like this:
V0207.Pants pantsMessage = new V0702.Pants();
That makes it very clear what version is being used. I could make this happen by creating the Pants message classes as inner classes of the V0207 class, but then the V0207 class becomes gigantic (there could be a hundred messages, each with 100 fields, for every given version). Is there possibly a way to #include an inner class, so they can be stored in separate files? This would be ideal.
I suppose I can emulate this with a wrapper class, that does something (silly?) like this, where there exists an instance of the Pants class in the V0207 object:
Object pantsMessage = V0207.pants.getClass().newInstance();
((com.mydomain.clothesmessage.v0207.messagedefinitions.Pants)pantsMessage).getZipperType();
But I dislike that. It looks contrived and requires try/catch and casting when in use. Terrible.
I could also use a factory. That would be a bit nicer, but requires a parent class (or interface) and would require casting when used, since each message has unique methods.
Message pantsMessage = V0207Factory.newMessage(V0207.PantsMessage);
((com.mydomain.clothesmessage.v0207.messagedefinitions.Pants)pantsMessage).getZipperType();
or
Message sockMessage = V0207Factory.newSock();
((com.mydomain.clothesmessage.v0207.messagedefinitions.Socks)sockMessage).getSmellLevel();
What are your thoughts? I'm using JDK 1.7, but 1.8 might be usable.
I initially solved this by using inner static classes in one gigantic "version" class. Thus, the use looked like this:
V0207.Pants pantsMessage = new V0702.Pants();
But the version class ('V0207') grew too quickly, especially as other developers on the team demanded a more "Java" way of setting the fields (which required a lot of getters and setters).
Thus, the final solution is to put the messages inside their own v0207.messages package name, and prepend each message with the version:
V0207_Pants pantsMessage = new V0702_Pants();
It's not as nice as using a C++ namespace, but it works. The version is clear to the reader, and the object can contain a lot of code without any files becoming too large.