Adapter allows classes with incompatible interfaces to work together, by converting the interface of one class into a form that a client expects. Basically you create an Adapter class as a go-between to convert messages from one interface to another.
There are two kinds:
- Object adapter: makes use of a toolkit/library class to implement its functionality.
- Class-based adapter: uses multiple inheritance to make use of another superclass's functionality. However Riel says we should Avoid multiple inheritance.
- You have an existing class (eg toolkit or library), but its interface doesn't fit in with your system
- You want to create a reusable class that cooperates with unrelated or unforeseen classes
- Object adapter only: You need to use several existing subclasses, but you don't want to adapt their interface by subclassing each one. Object adapters can adapt the interface of the parent class.
From Gang of Four Design Patterns book:
- Defines domain specific interface that a Client uses
- Collaborates with objects that implement the Target interface
- An existing interface that needs adapting
- Adapts the interface of Adaptee to the Target interface
Clients call operations on an Adapter object. The Adapter calls Adaptee operations to carry out the request.
From the Gang of Four Design Patterns book:
In this example we have a drawing editor with an editable Shape object that can draw itself. Implementing the Line subclass is reasonably simple, however if we need to display and edit text with the TextShape class it can be a lot harder to implement, and we may wish to use an existing toolkit called TextView. The problem is that TextView wasn't designed for the Shape class, so we need to adapt the interface without modifying the TextView toolkit (even if the toolkit was open source it would not make sense to modify a toolkit for one domain specific application).
The solution is to make TextShape an Adapter class, in this example we use the object adapter solution. Shapes boundingBox() requests are converted to the TextViews getExtent() request by TextShape. This allows the DrawingEditor to use the TextView class.
TextShape is also responsible for functionality that TextView doesn't provide. The diagram shows how TextShape implements the createManipulator() method of Shape.
You can find here a nicely explained java code example of the Adapter Pattern usage in the real world.
There are advantages and disadvantages to using object and class adapter.
- won't work when we want to adapt a class and its subclasses.
- lets Adapter override some of Adaptee's behavior.
- introduces only one object with no pointers needed to get to Adaptee.
- lets a single Adapter adapt any number of Adaptees.
- makes it harder than class adapter to override Adaptee functionality. To do this, we have to make an Adaptee subclass and access that from the Adapter.
- Bridge: The structure of Bridge looks similar but has a different intent. It aims to separate an interface from its implementation so they can be varied independently while adapter changes the interface of an existing object.
- Decorator: This pattern adds functionality to an object without changing its interface and also supports recursive composition which is not possible using adapters.
- Prototype: This pattern wraps up another object and does not change its interface.
- Proxy: A proxy appears similar to an adapter except it provides an identical interface and its intent is completely different. It is used to transparently perform some additional functions, while an adapter is used to provide an alternative interface.
Class adapter conflicts with several design maxims:
Creational: Abstract Factory | Builder | Factory Method | Prototype | Singleton