This article is fully based on Gamma's Design Patterns, Elements of Reusable Object-Oriented Software .
Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces. An other word for an adapter is a wrapper.
Sometimes a toolkit class that's designed for reuse isn't reusable only because its interface doesn't match the domain-specific interface an application requires.
Consider for example a drawing editor that lets users draw and arrange graphical elements (lines, polygons, text, etc.) into pictures and diagrams. The drawing editor's key abstraction is the graphical object, which has an editable shape and can draw itself. The interface for graphical objects is defined by an abstract class called Shape. The editor defines a subclass of Shape for each kind of graphical object: a LineShape class for lines, a PolygonShape class for polygons, and so forth.
Classes for elementary geometric shapes like LineShape and PolygonShape are rather easy to implement, because their drawing and editing capabilities are inherently limited. But a TextShape subclass that can display and edit text is considerably more difficult to implement, since even basic text editing involves complicated screen update and buffer management. Meanwhile, an off-the-shelf user interface toolkit might already provide a sophisticated TextView class for displaying and editing text. Ideally we'd like to reuse TextView to implement TextShape, but the toolkit wasn't designed with Shape classes in mind. So we can't use TextView and Shape objects interchangeably.
How can existing and unrelated classes like TextView work in an application that expects classes with a different and incompatible interface? We could change the TextView class so that it conforms to the Shape interface, but that isn't an option unless we have the toolkit's source code. Even if we did, it wouldn't make sense to change TextView; the toolkit shouldn't have to adopt domain-specific interfaces just to make one application work.
Instead, we could define TextShape so that it adapts the TextView interface to Shape's. We can do this in one of two ways:
- by inheriting Shape's interface and TextView's implementation
- by composing a TextView instance within a TextShape and implementing TextShape in terms of TextView's interface.
These two approaches correspond to the class and object versions of the Adapter pattern. We call TextShape an adapter or an wrapper.
Use the Adapter pattern when:
- you want to use an existing class, and its interface does not match the one you need.
- you want to create a reusable class that cooperates with unrelated or unforeseen classes, that is, classes that don't necessarily have compatible interfaces.
- (object adapter only) you need to use several existing subclasses, but it's impractical to adapt their interface by subclassing every one. An object adapter can adapt the interface of its parent class.
Two examples on how to implement an adapter or wrapper.
|Using Multiple Inheritance
|Using composition for an object Adapter
|Client (Drawing Editor)
|defines the domain-specific interface that Client uses.
|collaborates with objects conforming to the Target interface.
|defines an existing interface that needs adapting.
|adapts the interface of Adaptee to the Target interface.
- Clients call operations on an Adapter instance. In turn, the adapter calls Adaptee operations that carry out the request.
- Bridge, has a structure similar to an object adapter, but Bridge has a different intent: It is meant to separate an interface from its implementation so that they can be varied easily and independently. An adapter is meant to change the interface of an existing object.
- Decorator, enhances another object without changing its interface. A decorator is thus more transparent to the application than an adapter is. As a consequence, Decorator supports recursive composition, which isn't possible with pure adapters.
- Proxy, defines a representative or surrogate for another object and does not change its interface.
- Design Pattern, Elements of Reusable Object-Oriented Software, Erich Gamma, Ralph Johnson, Richard Helm, John Vlissides, First Published: October 21, 1994