Introduction to the ‘Adapter’ Design Pattern
The adapter design pattern is a very general concept that is leveraged in many large code bases. Its usage makes it very easy to extend a framework by allowing multiple classes to work with each other, without modifying the source-code for any of the source classes. It is, in essence, a central hook that can be used to glue many parts together to create a rich and diverse object hierarchy in an object-oriented code environment.
The adapter pattern is actually very easy to understand. It’s easy to directly relate it to adapters we usually encounter in our daily life. Think of the following physical analogy:
We obviously don’t want to create a separate ratchet for sockets of every possible size. Think of all the extra metal that would be necessary, or the extra weight that you would need to lug around in your tool bag. There should effectively be only a single ratchet that can be used to transmit the torque. These ratchets are analogous to the classes that may have been developed to perform something specific in a code-base. Every once in a while (and maybe more often than not), these classes may need to interoperate with classes of a different kind (think of ‘sockets’ of different sizes). Rather than rework either of the classes (i.e. have a separate ratchet for each socket in our analogy), it is more effective to introduce an adapter that can mediate their interoperability. In our example, this would be the adapter depicted in the lower right.
Why This is Helpful to Know
Sling, which is the web framework that powers AEM, leverages the adapter framework extensively. Anybody who has worked with AEM knows the mantra that ‘everything in sling is a resource’. However, the versatility of AEM is that this ‘resource’ can be leveraged as a common denominator to hundreds of other objects (classes) in AEM, each one of which is designed for its own specialized purpose. The adapter framework has allowed the interoperability of all these special classes in a simple and efficient way.
The Sling/AEM Object Hierarchy
Consider the following object hierarchy in AEM which is built on top of the Sling’s Adapter framework:
The above is only a small subset of a graph that was built from a handpicked set of AEM objects. The entire tree of adaptable components can be found in this link for AEM 6.1, and is vastly more complex. In the graph above, for every node-pair: TypeB —> TypeA, it is possible to get an object of TypeB given an object type TypeA, using the simple method:
TypeA objA = objB.adaptTo(TypeA);
Extending the Framework using a Custom AdapterFactory
It is, in fact, possible to extend the adapter framework in one’s own custom ways. This is possible by writing custom ‘AdapterFactory’ components into the AEM framework. In the example source code below, I’ve introduced an adaptor that allows objects of classes ‘Resource’ and ‘SourceObject’ to adapt to an object of the ‘TargetObject’ kind. I’ve omitted any source-view of the ‘SourceObject’ and ‘TargetResource’ classes. They could be thought of as custom business-related, plain-old Java classes (POJOs) introduced only to illustrate the following example:
The client code for using the new capability is as follows:
In a later post, we will see how we can leverage the AEM Sling Models to declare adapter factories via pure Java annotations. This highly speeds up the development process, allowing for many additional, convenient methods.