BIM492 DESIGN PATTERNS
07. ADAPTER AND
FACADE PATTERNS
Being Adaptive
Adapters all around us
Have you ever needed to use a US-made laptop in a European country?
Can you think different kinds of
? power adapters, or other kinds
of real-world adapters?
2
Object-oriented adapters
3
Remember our ducks? --> might be turkeys with an adapter
Let's review a simplified version of our Duck interfaces and classes
public interface Duck { public class MallardDuck implements Duck {
public void quack(); public void quack() {
public void fly(); System.out.println("Quack");
} }
public void fly() {
System.out.println("I'm flying");
}
}
public interface Turkey { public class WildTurkey implements Turkey {
public void gobble(); public void gobble() {
public void fly(); System.out.println("Gobble Gobble");
} }
public void fly() {
System.out.println("I'm flying a short distance");
}
}
4
We need an adapter
Now, let's say you're short
on Duck objects and you'd
like to use some Turkey
objects in their place.
Obviously, we can't use the
turkeys outright because
they have a different
interface
5
Test drive the adapter
6
The Adapter Pattern explained
Here's how the client uses the Adapter
1. The client makes a request to the
adapter by calling a method on it
using the target interface.
2. The adapter translates that
request into one or more calls on
the adaptee using the adaptee
interface.
3. The client receives the results of
the call and never knows there is
an adapter doing the translation
7
Sharpen your pencil
Let's say we also need an Adapter that converts a Duck to a Turkey. Let's call it DuckAdapter.
Write that class. public class DuckAdapter implements Turkey {
Duck duck;
Random rand;
public DuckAdapter(Duck duck) {
this.duck = duck;
rand = new Random();
}
public void gobble() {
duck.quack();
}
public void fly() {
if (rand.nextInt(5) == 0) {
duck.fly();
}
}
}
8
there are no
Dumb Questions
Q: How much "adapting" does an adapter need to do? It Q: Does an adapter always wrap one and only one class?
seems like if I need to implement a large target interface, I
A: The Adapter Pattern's role is to convert one interface into
could have a LOT of work on my hands.
another. While most examples of the adapter pattern show an
A: You certainly could. The job of implementing an adapter adapter wrapping one adaptee, we both know the world is
really is proportional to the size of the interface you need to often a bit more messy. So, you may well have situations
support as your target interface. Think about your options, where an adapter holds two or more adaptees that are needed
however. You could rework all your client-side calls to the to implement the target interface. This relates to another
interface, which would result in a lot of investigative work pattern called the Facade Pattern; people often confuse the
and code changes. Or, you can cleanly provide one class that two. Remind us to revisit this point when we talk about
encapsulates all the changes in one class. facades later.
Q: What if I have old and new parts of my system, the old parts expect the old vendor interface, but we've already written the
new parts to use the new vendor interface? It is going to get confusing using an adapter here and the unwrapped interface
there. Wouldn't I be better off just writing my older code and forgetting the adapter?
A: Not necessarily. One thing you can do is create a Two Way Adapter that supports both interfaces. To create a Two Way
Adapter, just implement both interfaces involved, so the adapter can act as an old interface or a new interface.
9
Adapter Pattern defined
Decouple client from the implemented
interface
If we expect the interface to change
over time, the adapter encapsulates
that change
It is full of good OO design principles
object composition to wrap the adaptee
we can use an adapter with any
subclass of the adaptee
binds the client to an interface, not an
implementation
we could use several adapters, each
converting a different backend set of
classes
10
Object and class adapters
There are actually two kinds of adapters: object adapters and class adapters
what we investigated was an object adapter
You need multiple inheritance to implement class adapters, which is not possible in Java
Look familiar?
Class adapter --> we subclass Target and Adaptee
Object adapter --> composition to pass requests to an Adaptee
11
Real world adapters
Let's take a look at the use of a simple Adapter in the real world
Old world Enumerators
If you've been around Java for a while you probably remember that the
early collections types (Vector, Stack, Hashtable, and a few others)
implement a method elements(), which returns an Enumeration. The
Enumeration interface allows you to step through the elements of a
collection without knowing the specifics of how they are managed in
the collection.
New world Iterators
When Sun released their more recent Collections classes they began
using an Iterator interface that, like Enumeration, allows you to
iterate through a set of items in a collection, but also adds the ability
to remove items.
And today...
We are often faced with legacy code that exposes the Enumerator
interface, yet we'd like for our new code to only use Iterators. It
looks like we need to build an adapter.
12
Adapting an Enumeration to an Iterator
First, let's look at the two interfaces to figure out how the methods map from one to the other.
Designing the adapter
13
Dealing with the remove() method
We know Enumeration is "read-
only", there is no way to
implement fully functioning
remove() method. public class EnumerationIterator implements Iterator {
Enumeration enum;
The best we can do is to throw
a runtime exception. public EnumerationIterator(Enumeration enum) {
this.enum = enum;
Luckily, designers of Iterator }
foresaw this need and added an
UnsupportedOperationException public boolean hasNext() {
.
return enum.hasMoreElements();
}
public Object next() {
return enum.nextElement();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
14
And now for something different…
We have seen Adapter Pattern -->
convert one interface of class into one
that a client is expecting
Now, the Facade Pattern --> alters the
interface, but for a different reason: to
simplify the interface
Hide complexity of one or more classes
behind a clean, well-lit facade
15
Home Sweet Home Theater
Let's take a look at a modern
obsession: building an own home
theater
You need -->
a DVD player
a projection video system
an automated screen
surround sound
and even a popcorn popper
Check out the components…
16
Watching a movie (the hard way)
Pick out a DVD, relax, and get ready for movie magic. Tasks
--> Oh, you need to perform a few tasks to watch the movie 1. Turn on the popcorn popper
2. Start the popper popping
3. Dim the lights
4. Put the screen down
5. Turn the projector on
6. Set the projector input to DVD
7. Put the projector on wide-screen mode
8. Turn the sound amplifier on
9. Set the amplifier to DVD input
10. Set the amplifier to surround sound
11. Set the amplifier volume to medium (5)
12. Turn the DVD Player on
13.Start the DVD Player playing
17
Let's check out those tasks of the hard way…
But there's more…
popper.on(); When the movie is over, how do
popper.pop(); you turn everything off?
lights.dim(10); How about listening to a CD or
radio?
screen.down(); If you upgrade the system, you
projector.on(); have to learn from the
projector.setInput(dvd); beginning.
projector.wideScreenMode();
amp.on(); How hard to watch a movie!
amp.setDvd(dvd);
amp.setSurroundSound(); Let's see what we can do with the
amp.setVolume(5);
FACADE PATTERN…
dvd.on();
dvd.play(movie);
18
Facade pattern takes a complex
Lights, Camera, Facade! subsystem and make it easier to use
by implementing a Facade class.
Facade class provides one, more
reasonable interface.
The power of the complex subsystem
is still there.
19
there are no
Dumb Questions
Q: Does each subsystem have only one facade?
A: Not necessarily. The pattern certainly allows for any
number of facades to be created for a given subsystem.
Q: What is the benefit of the facade other than the fact that I
now have a simpler interface?
A: The Facade Pattern also allows you to decouple your client
implementation from any one subsystem. Let's say for
instance that you get a big raise and decide to upgrade your
home theater to all new components that have different
interfaces. Well, if you coded your client to the facade rather
than the subsystem, your client code doesn't need to change,
just the facade (and hopefully the manufacturer is supplying
that!).
20
there are no
Dumb Questions
Q: So the way to tell the difference between the Adapter
Pattern and the Facade Pattern is that the adapter wraps one
class and the facade may represent many classes?
A: No! Remember, the Adapter Pattern changes the interface
of one or more classes into one interface that a client is
expecting. While most textbook examples show the adapter
adapting one class, you may need to adapt many classes to
provide the interface a client is coded to. Likewise, a Facade
may provide a simplified interface to a single class with a
very complex interface.
The difference between the two is not in terms of how many
classes they "wrap," it is in their intent. The intent of the
Adapter Pattern is to alter an interface so that it matches
one a client is expecting. The intent of the Facade Pattern is
to provide a simplified interface to a subsystem.
21
public class HomeTheaterFacade {
Amplifier amp;
Constructing your home theater facade
Tuner tuner;
DvdPlayer dvd; Let's step through the
CdPlayer cd;
Projector projector; construction of the
TheaterLights lights; HomeTheaterFacade…
Screen screen;
PopcornPopper popper;
The first step is to use
public HomeTheaterFacade(Amplifier amp,
Tuner tuner, DvdPlayer dvd, composition so that the facade
CdPlayer cd, Projector projector, has access to all the
Screen screen, TheaterLights lights,
PopcornPopper popper) { components of the subsystem:
this.amp = amp;
this.tuner = tuner;
this.dvd = dvd;
this.cd = cd;
this.projector = projector;
this.screen = screen;
this.lights = lights;
this.popper = popper;
}
// other methods here
}
22
public void watchMovie(String movie) { Implementing the
System.out.println("Get ready to watch a movie...");
popper.on(); simplified interface
popper.pop();
lights.dim(10);
screen.down();
projector.on();
projector.wideScreenMode();
amp.on();
amp.setDvd(dvd);
amp.setSurroundSound();
amp.setVolume(5);
dvd.on();
dvd.play(movie); Now it's time to bring the
}
components of the subsystem
public void endMovie() { together into a unified
System.out.println("Shutting movie theater down...");
popper.off(); interface.
lights.on();
screen.up();
projector.off(); Let's implement the
amp.off(); watchMovie() and
dvd.stop();
dvd.eject(); endMovie() methods:
dvd.off();
} 23
Time to watch a movie (the easy way)
It's SHOWTIME!
public class HomeTheaterTestDrive {
public static void main(String[] args) {
// instantiate components here
HomeTheaterFacade homeTheater =
new HomeTheaterFacade(amp, tuner, dvd,
cd, projector, screen, lights, popper);
homeTheater.watchMovie("Winter Sleep");
homeTheater.endMovie();
}
}
24
and the magic happens…
25
Facade Pattern defined
Facade Pattern --> create a class that
simplifies and unifies a set of more
complex classes that belong to some
subsystem.
Facade is fairly straightforward
It allows us to avoid tight
coupling between clients and
subsystems
Also helps us adhere to a new
object oriented principle.
26
The principle of least knowledge
BUT WHAT DOES THIS MEAN IN REAL TERMS?
It means when you are designing a system, for any object, be careful of the number of classes it
interacts with and also how it comes to interact with those classes.
This principle prevents us from creating designs that have a large number of classes coupled together
so that changes in one part of the system cascade to other parts.
How many classes is this code coupled to?
public float getTemp() {
return station.getThermometer().getTemperature;
}
27
How NOT to Win Friends and Influence Objects
The principle provides some guidelines.
Take any object, now from any method in that object, the principle
tells us that we should only invoke methods that belong to:
1. The object itself
2. Objects passed in as a parameter to the method
3. Any object the method creates or instantiates
4. Any components of the object
For example --> public float getTemp() {
Thermometer thermometer = station.getThermometer();
Apply the principle to the code }
return thermometer.getTemperature();
28
Applying the principle
public float getTemp() {
Thermometer thermometer = station.getThermometer();
return thermometer.getTemperature();
}
public float getTemp() {
return station.getTemperature();
}
29
Keeping your method calls in bounds…
public class Car {
Here's a Car class: Engine engine;
// other instance variables
demonstrates all
the ways you can public Car() {
call methods // initialize engine, etc.
}
and still adhere to public void start(Key key) {
the Principle of Doors doors = new Doors();
Least Knowledge:
boolean authorized = key.turns();
if (authorized) {
engine.start();
updateDashboardDisplay();
doors.lock();
}
}
public void updateDashboardDisplay() {
// update display
}
} 30
there are no
Dumb Questions
Q: There is another principle called the Law of Demeter; how Q: Are there any disadvantages to applying the Principle of
are they related? Least Knowledge?
A: The two are one and the same and you'll encounter these A: Yes; while the principle reduces the dependencies between
terms being intermixed. We prefer to use the Principle of objects and studies have shown this reduces software
Least Knowledge for a couple of reasons: maintenance, it is also the case that applying this principle
(1) the name is more intuitive and results in more "wrapper" classes being written to handle
method calls to other components. This can result in
(2) the use of the word "Law" implies we always have to increased complexity and development time as well as
apply this principle. In fact, no principle is a law, all decreased runtime performance.
principles should be used when and where they are
helpful. All design involves tradeoffs (abstractions
versus speed, space versus time, and so on) and while
principles provide guidance, all factors should be taken
into account before applying them.
31
Sharpen your pencil
Do either of these classes violate the Principle of least Knowledge? Why or why not?
public House {
WeatherStation station;
// other methods and constructor
public float getTemp() {
return station.getThermometer().getTemperature();
}
public House {
}
WeatherStation station;
// other methods and constructor
public float getTemp() {
Thermometer thermometer = station.getThermometer();
return getTempHelper(thermometer);
Can you think of a common use of }
Java that violates the Principle of public float getTempHelper(Thermometer thermometer) {
Least Knowledge? return thermometer.getTemperature();
}
} 32
The Facade and
The Principle of Least Knowledge
33
Tools for your Design Toolbox
Bullet Points
When you need to use an existing class and its interface is
not the one you need, use an adapter.
When you need to simplify and unify a large interface or
complex set of interfaces, use a facade.
An adapter changes an interface into one a client expects.
A facade decouples a client from a complex subsystem.
Implementing an adapter may require little work or a great
deal of work depending on the size and complexity of the
target interface.
Implementing a facade requires that we compose the facade
with its subsystem and use delegation to perform the work
of the facade.
An adapter wraps an object to change its interface, a
decorator wraps an object to add new behaviors and
responsibilities, and a facade "wraps" a set of objects to
simplify.
34