The Adapter Pattern
Putting a Square Peg in a Round Hole!
Wrapping Objects to Unify Interfaces
Question: What pattern wraps objects to give them new functionality? Now we wrap objects with a different purpose:
To make their interfaces look like something they are not To simplify the interfaces of objects
Adapters
Real world is full of them!
Some examples?
Object oriented adapters
Scenario: you have an existing software system that you need to work a new vendor library into, but the new vendor designed their interfaces differently than the last vendor.
Your Existing System Vendor Class Their interface doesnt match the one youve written your code against. Not going to work!
The adapter implements the interface your classes Your Existing expect System
What to do? Write a class that adapts the new vendor interface into the one youre expecting. And talks to the vendor interface to service
your requests Adapter Vendor Class
==
Your Existing Adapter System New code
Vendor Class No code changes
No code changes
If it walks like a duck..
If it walks like a duck and quacks like a duck, then it might be a duck turkey wrapped with a duck adapter.
public interface Duck { public void quack (); public void fly (); } public class MallardDuck implements Duck { public void quack () { [Link](Quack); } public void fly ( ) { [Link] (I am flying); } }
Meet the fowl!
public interface Turkey { public void gobble (); public void fly ( ); } public class WildTurkey implements Turkey { public void gobble ( ) { [Link](Gobble Gobble); } public void fly ( ){ [Link](Im flying a short distance); } }
Concrete implementations are similar -- just print out the actions.
Now.
Lets say you are short on Duck objects and would like to use some Turkey objects in their place. Cant use them outright because they have a different interface.
public class TurkeyAdapter implements Duck { Turkey turkey; public TurkeyAdapter (Turkey turkey) { [Link] = turkey; } Next, we need to get a reference to the object that we public void quack ( ) { are adapting; here we do that through the constructor. [Link] ( ); } public void fly ( ){ Now we need to implement all the methods in the for (int j = 0; j<5; j++) interface; the quack() translation between classes is easy; [Link] ( ); just call the gobble method. } } Even though both interfaces have a fly ( ) method, Turkeys fly in } short spurts -- they cant do long distance flying like ducks. To map between a Ducks fly ( ) method and a Turkeys we need to call the Turkeys fly ( ) method five times to make up for it. First, you need to implement the interface of the type you are adapting to. This is the interface your client expects.
The Adapter Pattern Defined
The Adapter Pattern converts the interface of a class into another interface the clients expect. Adapter lets classes work together that couldnt otherwise because of incompatible interfaces.
Client
The client sees only the Target interface.
<<Interface>> Target request ( )
The Adapter implements the target interface
Full of good OO design principles: --Use of object composition --Pattern binds the client to an interface and not an implementation
Adapter request ( )
Adaptee specificRequest ()
Adapter is composed with the Adaptee
All requests get delegated to the Adaptee
Object and Class Adapters
There are two types of Adapters
Object Adapter : what we have seen so far. Class Adapter: not as common as it uses multiple inheritance, which isnt possible in Java.
Client <<Interface>> Target request ( ) Adaptee specificRequest ()
Difference: The only difference is that with class adapter we subclass the Target and the Adaptee, while the object adapter uses composition to pass requests to an adaptee.
Adapter request ( )
Question: Object Adapters and Class Adapters use two different means of adapting the adaptee (composition versus inheritance). How do these implementations affect the flexibility of the adapter?
Real World Adapters
Old world Enumerators
<<interface>> Enumeration hasMoreElements ( ) nextElement ( )
Enumeration has a simple interface. Tells whether there are any more elements in the collection. Returns the next element Tells you if you have looked at all the elements Gets the next one
New world Iterators
<<interface>> Iterator hasNext ( ) next ( ) remove ( )
And todaylegacy code that exposes the Enumerator interface. Yet we want new code to use Iterators. Need an adapter.
Removes an item from the collection
Adapting an Enumeration to an Iterator
First step: examine the two interfaces
Target interface These two methods look easy, they map straight to hasNext ( ) and next ( ) in Iterator
<<interface>> Iterator hasNext ( ) next ( ) remove ( )
<<interface>> Enumeration hasMoreElements ( ) nextElement ( )
Adaptee interface
But what about this method remove ( ) in Iterator? Theres nothing like that in Enumeration.
Designing the Adapter
Your new code gets to use Iterators, even if theres really an Enumeration underneath.
<<interface>> Iterator hasNext ( ) next ( ) remove ( )
We are making the Enumerations in your old code look like Iterators for your new code.
A class implementing the Enumeration interface is the adaptee.
EnumerationIterator is the Adapter
EnumerationIterator hasNext ( ) next ( ) remove ( )
<<interface>> Enumeration hasMoreElements () nextElement ()
Dealing with the remove ( ) method
Enumeration is a read only interface - it does not support the remove ( ) method.
Implies there is no real way to implement a fully functioning remove () method. The best that can be done is to throw a runtime exception. Iterator designers foresaw the need and have implemented an UnsupportedOperationException.
Here the adapter is not perfect but is a reasonable solution as long as the client is careful and the adapter is well-documented.
EnumerationIterator - The Code
public class EnumerationIterator implements Iterator { Enumeration enum; public EnumerationIterator (Enumeration enum) { [Link] = enum; } public boolean hasNext () { return [Link] ( ); } public Object next ( ) { return [Link] ( ); } public void remove ( ) { throw new UnsupportedOperationException ( ); } }
Since we are adapting Enumeration to Iterator, the EnumerationIterator must implement the Iterator interface -- it has to look like the Iterator. The Enumeration we are adapting. Were using composition so we stash it in an instance variable. hasNext ( ) and next () are implemented by delegating to the appropriate methods in the Enumeration. For the remove ( ) we simply throw an exception.
Question: Some AC adapters do more than just change the interface -- they add other features like surge protection, indicator lights, and other bells and whistles. If you were going to implement these kinds of features, what pattern would you use?
Summary
When you need to use an existing class and its interface is not the one you need, use an adapter. An adapter changes an interface into one a client expects. Implementing an adapter may require little work or a great deal of work depending on the size and complexity of the target interface. There are two forms of adapter patterns: object and class adapters. Class adapters require multiple inheritance. An adapter wraps an object to change its interface, a decorator wraps an object to add new behaviors and responsibilities.