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. 139

Purpose

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.

UML class diagram: Adapter inherits from Target and holds a reference to Adaptee, forwarding request() to specificRequest().
The object adapter. Adapter is a Target by inheritance and has an Adaptee by composition, so 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.

UML class diagram: Adapter inherits from both Target and Adaptee.
The class adapter inherits from both sides. Cleaner on paper, and unavailable in most of the languages people actually ship in.

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.

UML class diagram: Adapter inherits from OldController and holds a NewController, translating moveVertical into rotateXaxis.
The arrangement as it was actually built. Adapter presents the old vertical and horizontal interface and converts each call into the new arm's rotational 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));
    }
}
The implementation. Note that the two adapted methods are the entire pattern: everything interesting happens inside 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.