When developing any kind of code interface, whether it is an elegant object oriented package or one of those ugly “Service” classes that we are so accustomed to, it is obvious that it should be as extensible as possible and require as little maintenance as possible. This applies, of course, to the input and output parameters (returned types), especially if the code in question cannot be modified by its clients.
Question is, how can we have flexible parameters if they consist of dumb get/set models? Each time a new field/attribute is required, someone will knock on your door to update your interface because otherwise they won’t be able to send or receive all the data they need.
Take the bellow example:
Person is a get/set class, having a
lastName and an
id. When the user of this interface will need to receive or send more attributes they won’t be able to, so they’ll ask you to first alter the
Person model and then add logic in your code to handle those attributes.
The solution to this problem is Polymorphism, one of the most common OOP principles – it will make our parameters “transparent” and more maintainable. Assuming that our data is represented in JSON, here is how I would redesign the
Person fetch (
insert (JsonObject person);
There are two big changes:
Person is actually an interface, extending
javax.json.JsonObject and at the same time animating some parts of the underlying json or maybe all of it – this way, if
People.fetch(...) changes and returns a bigger
JsonObject, the new values will be accessible automatically via
JsonObject.getString(...) method, until we may add more reading method to the
The second change is the input that
insert(...) method expects. It now requires a raw
JsonObject for the same reason: if the encapsulated service decides to expect more values, the user will simply add them to the
JsonObject. This may sound like an ugly solution since they might use it like this:
People people = ...
The above is quite ugly, the building of the JsonObject means duplicated logic. However, the user should realise that they can implement the interface
PersonInput extends JsonObject – all that building logic would be in the constructor of the
PersonInput implementation, while calls to
people.insert(...) will look like this:
People people = ...
JsonObject input parameter there is still one more question: how should the client know what values to provide? This is the part where JavaDocs come in the play: it should all be thoroughly documented in the method’s JavaDoc. I guess you can call it a good trade-off: the user has to do a little study before using your method but, on the other hand, the decoupling is very convenient for both of you.
The exact approach described above I used in the development of docker-java-api. Most methods which are creating something on the server are expecting
JsonObject as input and are returning interfaces which extend
JsonObject (see, for instance, Containers.create(…) and Container) – thus, if Docker’s API will evolve to require different Json inputs or return different Jsons, I won’t necessarily have to change any models any time soon.
P.S. I hope you noticed the keyword in this article is “interface”. It’s yet another example of why interfaces are very important tools that any object should make use of.