Home Design Patterns Adapter
Adapter
Structural Gang of Four“Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.”
Gamma, Helm, Johnson & Vlissides, p. 139Purpose
The Adapter is used when you have two existing classes that need to work together but don't know how. The adapter translates for the client. If the classes are being designed from scratch, another pattern such as a Bridge will probably work better.
That "already existing" part is the whole point. An adapter is a repair, not a design. You reach for it when the code you control has to meet code you don't: a vendor library, a legacy module, an acquired product, or an API that changed underneath you.
Design
There are two ways to build an adapter. The class adapter uses multiple inheritance. The object adapter holds an instance. Depending on your application, one or the other may be more attractive.
Object adapter
The object method may require a little extra work to write the forwarding calls, but it has real advantages. All of the problems created by multiple inheritance simply don't arise: no broken encapsulation, no diamond problem, no worrying about compiler support. It can also be pointed at any subclass of the adaptee at runtime, which the inherited version cannot.
request() can be implemented
as a call to specificRequest().Class adapter
Choosing the class route may result in a simpler design, and it may take less programming effort. If two functions have the same signature and represent the same functionality, the class adapter may not have to adapt that method at all. It just works. It can also override adaptee behavior in ways the object adapter cannot.
The costs are significant, though. Many languages do not support true multiple inheritance. There is some loss of encapsulation, and overlapping method names can cause real confusion. Sometimes it simply isn't available: if you don't have the source and the original developer made a method you need private, inheritance won't reach it.
Example
Autobot Robotics, developer of a robotic arm, just acquired a new division with a new product. This new arm uses a different interface to control it than the previous one did. The team decided to add an adapter to the current application so it could drive the new arm without rewriting everything that already talked to the old one.
class OldController
{
public void moveVertical(int inch) {
// some code
}
public void moveHorizontal(int inch) {
// some code
}
}
class NewController
{
public void rotateXaxis(int degree) {
// some code
}
public void rotateYaxis(int degree) {
// some code
}
}
class Adapter : OldController
{
NewController adaptee = new NewController();
public void moveVertical(int inch) {
adaptee.rotateXaxis(convert.x(inch));
}
public void moveHorizontal(int inch) {
adaptee.rotateYaxis(convert.y(inch));
}
}
convert.Comparisons
- Bridge is the closest relative. The difference is timing. An Adapter is applied to systems after they are designed, a Bridge before.
- Facade is similar to an adapter connected to many adaptees at once, though a Facade aims to simplify rather than to translate.
- Decorator enhances an object without changing its interface, so it is more transparent to the client.
- Proxy keeps the same interface too, but its job is controlling access rather than adding behavior.
Why It Exists
My take
Adapter exists because software outlives the assumptions it was written under, and because you almost never own both sides of an interface. The pattern is really an admission about the industry. Code arrives from acquisitions, vendors, and your own past self, and none of it agreed on names in advance.
What the pattern buys you is a place to put the mismatch. Without it, the translation still happens. It just gets smeared across every call site as a little bit of conversion here and a special case there. Two years later nobody can tell you where the boundary between the two systems is, because there isn't one. An adapter concentrates all of that into a class whose entire reason for existing is visible in its name.
It is also the pattern most likely to be temporary, and that is fine. When the old arm is finally retired, you delete one class. That is a much better position than deleting a hundred scattered conversions.
Criticisms
The adapter pattern seems to be a well-liked pattern with few critics. The one caution I would add is that adapters accumulate. Each one is cheap and obviously justified, and a system with fifteen of them is telling you that the real problem is upstream, that you never picked a canonical model for your own domain. At that point the fix isn't a sixteenth adapter.