| Type | Structural |
| Purpose | Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces. |
Description
The Adapter pattern is a structural design pattern that allows two otherwise incompatible interfaces to work together. It is especially useful when new functionality must interact with existing code whose interface cannot easily be changed, often because of tight coupling, legacy dependencies, or other practical constraints.
The pattern works by wrapping an existing class in an adapter that presents the interface the client expects. In this way, the adapter translates one interface into another without requiring changes to either the client or the adapted class. Adapter is therefore used to connect classes that were not originally designed to collaborate.
It provides a way to reuse existing functionality through a new interface, making integration possible where direct interaction would otherwise fail.
Adapter is primarily concerned with making incompatible interfaces work together.
Overview
| Target | Target is the interface that clients call on. |
| Adapter | Adapter is what translates the Target requests to Adaptee. |
| Adaptee | Adaptee is the existing component which has the operations that need adapting. |
Implementation (Object Adapter)
This first example shows the Object Adapter accepting the adaptee as an instance in its constructor:
// Existing way requests are implemented
class Adaptee
{
public void SpecificRequest()
{
// Implementation code
}
}
// New standard for requests
interface ITarget
{
// Roughly equivalent to SpecificRequest
void Request();
}
// Implementing the new standard in terms of the old
class Adapter : ITarget
{
private Adaptee _adaptee;
public Adapter(Adaptee adaptee)
{
_adaptee = adaptee;
}
public void Request()
{
// Delegate to Adaptee
_adaptee.SpecificRequest();
}
}
Implementation (Class Adapter)
A C++ example shows the Class Adapter using multiple inheritance to adapt one interface to another:
// Old interface
class Adaptee {
public:
void SpecificRequest() { /* ... */ }
};
// New interface
class Target {
public:
virtual void Request() = 0;
};
// Class Adapter
class Adapter : public Target, private Adaptee {
public:
void Request() override {
// delegating the request
SpecificRequest();
}
};
In this C++ example:
| Adaptee | The existing component which has operations that need adapting. |
| Target | The interface that clients call on. |
| Adapter | Translates the Target requests to Adaptee. It does this by inheriting both the Target and the Adaptee. |
Notes
The choice between a Class Adapter and an Object Adapter in C++ depends on the needs of your project:
| Inheritance vs. Composition | A Class Adapter uses inheritance to connect the Adaptee to the Adapter. In contrast, an Object Adapter uses composition, wherein the Adapter contains an instance of the Adaptee. Generally, composition is favoured over inheritance because it often provides greater flexibility and reduces coupling between the Adapter and the Adaptee's implementation. |
| Adapting Subclasses | An Object Adapter can work with the Adaptee and its subclasses through composition and polymorphism. A Class Adapter is tied directly to the Adaptee class it inherits from, making it less flexible when different Adaptee implementations need to be supported. |
| Overriding Behavior | If you need to override some behavior of the Adaptee, using a Class Adapter can simplify this. However, with an Object Adapter, you can add this functionality by adding a new subclass of the Adaptee and passing it to the Adapter. |
Summary
Unless there are specific reasons to use a Class Adapter, such as needing to override some of the Adaptee's behaviour through inheritance, an Object Adapter is generally the more flexible choice because it relies on composition and can work with different compatible Adaptee instances.
For more information, please see here.