Raise your hand if you remember the golden hammer of Object Oriented Programming. You know, where you only have to code something once and then reuse it in all your subclasses? Remember those days?
Maybe this is what they still teach in dusty lecture halls amidst today’s Computer Science departments. But if you have spent any significant time coding in the trenches, you will have come to realize the lie that this mantra is.
You see, grandiose hierarchies of objects over time become nigh impossible to manage. At a certain point, one more subclass bolted onto the grand structure is deemed impossible and you must fork the solution. No, there is a different structure out there that we must adopt. And Spring is the platform that carries its banner.
Interface Oriented Programming. Let’s call it IOP since there aren’t enough acronyms in our industry. IOP is the premise that different slices and layers should talk to outsiders through a nice, clean interface. The backing service on the other side should provide a concrete implementation, but the caller need not know about it.
Why do I mention Spring as the champion of IOP? Because Rod Johnson’s foray onto the Java scene was to craft a dependency injector whereby this interface-based contract could be satisfied. Before I learned of Spring, the concept of Java interfaces was foreign. Sure they were mentioned in my college textbook Java in a Nutshell (dating myself?) but I saw little value in using them. Why?
Because when you are “newing” everything yourself, there appears little value in defining an interface and then assigning the object to it. You already know what is! What is to be gained from all the extra typing? But delegate that task to a DI container, and suddenly the cost vanishes. Expressing dependency graphs between beans with interfaces becomes much smoother when the container takes over the job of creating everything.
This goes along with the Liskov Principle where you can plug in any implementation without knowing what it is. Now sometimes people drag out the old square-is-a-rectangle example. I hate that one because geometry is a terrible domain to model semantic software concepts.
Digging in, interfaces don’t have to be complex. Instead, think of a handful of “getters” and go from there.
This fragment is part of an ongoing effort to add Affordances to Spring HATEOAS. Since we might support multiple web frameworks, having a clean, unencumbered interface is critical for getting started. It also helps avoid saddling the interface with details from Spring MVC, Spring WebFlux, or JAX-RS. Instead, this interface avoids all of that, forcing the concrete details to be nicely contained apart from each other.
Abstract classes and long hierarchies are often tricky to evolve over time, so I try to dodge that as much as possible. Composition of objects through IOP-driven strategies tends to be more amenable to change. Having said all that, what happens when you need this?
This is ONLY an abstract class because the project is currently on Java 6 and we can’t plugin a default implementation for supports(). With Java 8, this whole thing can be rolled back into an interface. Abstract vs. default interface methods aside, this is the NEW OOP. Do as much as you can to code 1 interface-to-many classes, avoiding intermediaries. Sometimes it’s unavoidable, but don’t give up too fast.
Let IOP be your OOP.
And the more you learn about the whole code base, be willing to revisit some of those hierarchies and see if you can’t “move around” stuff to get away from the hierarchies. You might be surprised at how perky your code becomes. Some of those requested features might suddenly seem possible.