Published September 7, 2020
by Doug Klugh
Promote the reuse of existing classes by changing their interfaces into ones that are compatible with other classes. This can be accomplished by creating a new class (Adapter) that implements the interface (Target) and delegates to the original implementation (Adaptee) through object composition. This will dynamically connect the Client to the Adaptee without either of them having knowledge of each other — providing a high level of isolation and flexibility.
The following two forms of the Adapter Pattern can be used to achieve different advantages. It all comes down to deciding which advantages are most important and what you're willing to trade to gain the benefits.
This form of the Adapter Pattern uses multiple inheritance to adapt one interface to another. While this form is simpler than the Object Form, it is also more rigid — as inheritance causes rigidity. Because once you create the Light Adapter (shown in the UML below in Figure 1), you cannot change to which Light (adaptee) it adapts — unlike the Object Form which assigns the adaptee dynamically at run time.
This form of the Adapter Pattern uses object composition to adapt one interface to another. While this form is more flexible than the Class Form, it is also more complex due to the use of composition. As illustrated below in Figure 2, you must create the Switchable Adapter object and bind the light object to it. Although now you can easily change which switchable object the adapter holds at run time, controlling which object the switch turns on and off by simply calling a set function in the adapter.
The Adapter Pattern is useful for insulating clients from services. Which form you choose depends on what you need and what you're willing to accept. Choose the object form if you need the flexibility and are willing to accept its complexity. Or choose the class form if you need the simplicity and are willing to accept its rigidity. The Adapter Pattern effectively provides isolation either way.