You are on page 1of 13

TheAdapterPattern

PuttingaSquarePeginaRound
Hole!

WrappingObjectstoUnifyInterfaces
Question:Whatpatternwrapsobjectstogivethemnew
functionality?
Nowwewrapobjectswithadifferentpurpose:
Tomaketheirinterfaceslooklikesomethingtheyarenot
Tosimplifytheinterfacesofobjects

Adapters
Realworldisfullofthem!
Someexamples?

Objectorientedadapters
Scenario:youhaveanexistingsoftwaresystemthatyouneedtoworka
newvendorlibraryinto,butthenewvendordesignedtheirinterfaces
differentlythanthelastvendor.
Your Existing
System

Vendor
Class

Their interface doesnt match the one youve


written your code against. Not going to work!

Whattodo?Writeaclassthatadaptsthenewvendorinterfaceintotheone
And talks to the vendor interface to service
youreexpecting.

The adapter
implements
the
interface
your classes
Your Existing
expect
System

your requests

Adapter

Vendor
Class

==

No code changes

Your Existing Adapter


System

New code

Vendor
Class
No code changes

Ifitwalkslikeaduck..
Ifitwalkslikeaduckandquackslikeaduck,thenit
mightbeaduckturkeywrappedwithaduckadapter.
public interface Duck {
public void quack ();
public void fly ();
}
public class MallardDuck implements Duck {
public void quack () {
System.out.println(Quack);
}
public void fly ( ) {
System.out.println (I am flying);
}
}

Meetthefowl!

public interface Turkey {


public void gobble ();
public void fly ( );
}

public class WildTurkey implements Turkey {


public void gobble ( ) {
System.out.println(Gobble Gobble);
}
public void fly ( ){
System.out.println(Im flying a short distanc
}
}

Concrete implementations are similar -- just print out the actions.

Now.
LetssayyouareshortonDuckobjectsandwouldliketousesome
Turkeyobjectsintheirplace.
Cantusethemoutrightbecausetheyhaveadifferentinterface .
First, you need to implement the interface of
the type you are adapting to. This is the
interface your client expects.

public class TurkeyAdapter implements Duck {


Turkey turkey;
public TurkeyAdapter (Turkey turkey) {
this.turkey = 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.
turkey.gobble ( );
}
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;
turkey.fly ( );
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.

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

<<Interface>>
Target
request ( )

Client
The client sees only the
Target interface.

Full of good OO design principles:


--Use of object composition
--Pattern binds the client to an
interface and not an implementation

The Adapter implements the target


interface

Adapter
request ( )

Adaptee
specificRequest ()

Adapter is composed with


the Adaptee

All requests get delegated to the Adaptee

ObjectandClassAdapters
TherearetwotypesofAdapters
ObjectAdapter:whatwehaveseensofar.
ClassAdapter:notascommonasitusesmultipleinheritance,whichisnt
possibleinJava.
Adaptee
specificRequest ()

<<Interface>>
Target
request ( )

Client

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?

RealWorldAdapters

OldworldEnumerators

NewworldIterators

Andtodaylegacycodethatexposes
theEnumeratorinterface.Yetwewant
newcodetouseIterators.Needan
adapter.

<<interface>>
Enumeration
hasMoreElements ( )
nextElement ( )

<<interface>>
Iterator
hasNext ( )
next ( )
remove ( )

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

Removes an item
from the
collection

AdaptinganEnumerationtoan
Iterator
Firststep:examinethetwointerfaces
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.

DesigningtheAdapter
Your new code
gets to use
Iterators, even
if theres
really an
Enumeration
underneath.

EnumerationIterator
is the Adapter

<<interface>>
Iterator
hasNext ( )
next ( )
remove ( )

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

<<interface>>
Enumeration
hasMoreElements ()
nextElement ()

Dealingwiththeremove()method
Enumerationisareadonlyinterfaceitdoesnot
supporttheremove()method.
Impliesthereisnorealwaytoimplementafullyfunctioning
remove()method.
Thebestthatcanbedoneistothrowaruntimeexception.
Iteratordesignersforesawtheneedandhaveimplementedan
UnsupportedOperationException.

Heretheadapterisnotperfectbutisareasonable
solutionaslongastheclientiscarefulandtheadapteris
welldocumented.

EnumerationIteratorTheCode
public class EnumerationIterator implements Iterator {
Enumeration enum;
public EnumerationIterator (Enumeration enum) {
this.enum = enum;
}
public boolean hasNext () {
return enum.hasMoreElements ( );
}
public Object next ( ) {
return enum.nextElement ( );
}
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
Whenyouneedtouseanexistingclassanditsinterfaceisnotthe
oneyouneed,useanadapter.
Anadapterchangesaninterfaceintooneaclientexpects.
Implementinganadaptermayrequirelittleworkoragreatdealof
workdependingonthesizeandcomplexityofthetargetinterface.
Therearetwoformsofadapterpatterns:objectandclassadapters.
Classadaptersrequiremultipleinheritance.
Anadapterwrapsanobjecttochangeitsinterface,adecorator
wrapsanobjecttoaddnewbehaviorsandresponsibilities.

You might also like