Table of Contents
What is the Adapter Pattern?
The definition of the Adapter Pattern from both Design Patterns: Elements of Reusable Object-Oriented Software and Head First Design Patterns: A Brain-Friendly Guide is
The Adapter Pattern converts the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.
Adapter Pattern Class Diagram Explained
The diagram shown above represents the generic class diagram of the Adapter Pattern. We start with the Client object. It is directly associated with the Target interface but expects the behavior of the Adaptee object. The problem is our Adaptee object does not implement the Target interface the Client has access to. Enter the Adapter class. It will implement the Target interface and delegate the behavior using composition to the Adaptee object. So in this diagram, when the Client calls Request() via the Target interface, the Adapter makes the SpecificRequest() to the Adaptee. This is considered an object adapter. There is another version of the Adapter pattern called a class adapter where the Adapter class inherits from the Adaptee class. The object adapter is the preferred adapter due to it supporting a common design principle to prefer composition over inheritance. Additionally, some languages don’t allow multiple inheritance (i.e. Java) so the object adapter is the only option.
Adapter Pattern Example
So now that we have the basic understanding of the pattern, let’s apply it. Consider a Dog interface that has an abstract method Bark(). Say, for the moment, there is only one subclass, LivingDog. It implements Bark(). Additionally, we have a class called RobotDog that implements a PlayBarkingSound() method. What if we have some new work that requires a client to treat RobotDog like a Dog? We could have RobotDog inherit from Dog but the existing interfaces don’t quite line up and we would rather not modify the existing RobotDog class (open/closed principle). Here is where the Adapter pattern comes in. Our Dog interface would be considered our Target and the RobotDog class would be our Adaptee. So we would need an Adapter class to implement the Dog interface and delegate the behavior we want to the RobotDog class. Let’s call our Adapter class the RobotDogAdapter. We decide to implement the behavior of Bark() to just call RobotDog’s PlayBarkingSound() method. Now since we are delegating the behavior through composition this is an example of an object adapter. The alternative would be a class adapter pattern that would have the RobotDogAdapter privately inherit from RobotDog. The object adapter pattern is preferred by most so we will just stick with it as our example. Below is the class diagram of our object adapter.
Example written in C++
Here is a C++ implementation of our example.
Dog.h
LivingDog.h
LivingDog.cpp
RobotDog.h
RobotDog.cpp
RobotDogAdapter.h
RobotDogAdapter.cpp
DogTest.cpp
Examining DogTest.cc, we create a LivingDog object and call Bark() via the Dog interface to show how it works. Then we create our RobotDog and pass it in to the creation of our RobotDogAdapter class. We call Bark() via the Dog interface just like we did for LivingDog. When we run DogTest.cc we see this output:
Chester is barking!
Sony's Aibo is playing barking sound
So we see that Bark() ultimately executes the PlayBarkingSound() method in RobotDog as we had intended.
You can find the full code here
Benefits of the Adapter Pattern
So now that we have seen the Adapter pattern in action, let’s go over the benefits of using the pattern.
- In the object adapter pattern, the Adapter class can be used with any subclass of the Adaptee. However, it can be difficult to override Adaptee behavior as you may need to have the Adapter class use subclasses of the Adaptee versus the Adaptee itself.
- The client is decoupled from the incompatible interface and not affected by changes to that interface because the adapter class encapsulates the incompatible interface.
Recommended Resources
Here are some resources I recommend for more information on the Adapter Pattern
Head First Design Patterns: A Brain-Friendly Guide
Design Patterns: Elements of Reusable Object-Oriented Software
In Closing
There you have it. If you followed along, I hope you now have a better understanding of the Adapter Pattern. Please feel free to leave comments and feedback. Much appreciated!