Chapter 7. The Adapter and Facade Patterns: Being Adaptive

image with no caption

In this chapter we’re going to attempt such impossible feats as putting a square peg in a round hole. Sound impossible? Not when we have Design Patterns. Remember the Decorator Pattern? We wrapped objects to give them new responsibilities. Now we’re going to wrap some objects with a different purpose: to make their interfaces look like something they’re not. Why would we do that? So we can adapt a design expecting one interface to a class that implements a different interface. That’s not all; while we’re at it, we’re going to look at another pattern that wraps objects to simplify their interface.

Adapters all around us

You’ll have no trouble understanding what an OO adapter is because the real world is full of them. How’s this for an example: Have you ever needed to use a US-made laptop in Great Britain? Then you’ve probably needed an AC power adapter...

image with no caption

You know what the adapter does: it sits in between the plug of your laptop and the British AC outlet; its job is to adapt the British outlet so that you can plug your laptop into it and receive power. Or look at it this way: the adapter changes the interface of the outlet into one that your laptop expects.

Note

How many other real-world adapters can you think of?

Some AC adapters are simple—they only change the shape of the outlet so that it matches your plug, and they pass the AC current straight through—but other adapters are more complex internally and may need to step the power up or down to match your devices’ needs.

Okay, that’s the real world; what about object-oriented adapters? Well, our OO adapters play the same role as their real-world counterparts: they take an interface and adapt it to one that a client is expecting.

Object-oriented adapters

Say you’ve got an existing software system that you need to work a new vendor class library into, but the new vendor designed their interfaces differently than the last vendor:

image with no caption

Okay, you don’t want to solve the problem by changing your existing code (and you can’t change the vendor’s code). So what do you do? Well, you can write a class that adapts the new vendor interface into the one you’re expecting.

image with no caption

The adapter acts as the middleman by receiving requests from the client and converting them into requests that make sense on the vendor classes.

image with no caption

Note

Can you think of a solution that doesn’t require YOU to write ANY additional code to integrate the new vendor classes? How about making the vendor supply the adapter class?

If it walks like a duck and quacks like a duck, then it must might be a duck turkey wrapped with a duck adapter...

It’s time to see an adapter in action. Remember our ducks from Chapter 1? Let’s review a slightly simplified version of the Duck interfaces and classes:

image with no caption
image with no caption

Here’s a subclass of Duck, the MallardDuck.

image with no caption

Now it’s time to meet the newest fowl on the block:

image with no caption
image with no caption

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.

So, let’s write an Adapter:

Test drive the adapter

Now we just need some code to test drive our adapter:

image with no caption
image with no caption

The Adapter Pattern explained

Now that we have an idea of what an Adapter is, let’s step back and look at all the pieces again.

image with no caption

Here’s how the Client uses the Adapter

  • ① The client makes a request to the adapter by calling a method on it using the target interface.

  • ② The adapter translates the request into one or more calls on the adaptee using the adaptee interface.

  • ③ The client receives the results of the call and never knows there is an adapter doing the translation.

Note

Note that the Client and Adaptee are decoupled – neither knows about the other.

Adapter Pattern defined

Enough ducks, turkeys, and AC power adapters; let’s get real and look at the official definition of the Adapter Pattern:

Note

The Adapter Pattern converts the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.

Now, we know this pattern allows us to use a client with an incompatible interface by creating an Adapter that does the conversion. This acts to decouple the client from the implemented interface, and if we expect the interface to change over time, the adapter encapsulates that change so that the client doesn’t have to be modified each time it needs to operate against a different interface.

We’ve taken a look at the runtime behavior of the pattern; let’s take a look at its class diagram as well:

image with no caption

The Adapter Pattern is full of good OO design principles: check out the use of object composition to wrap the adaptee with an altered interface. This approach has the added advantage that we can use an adapter with any subclass of the adaptee.

Also check out how the pattern binds the client to an interface, not an implementation; we could use several adapters, each converting a different backend set of classes. Or, we could add new implementations after the fact, as long as they adhere to the Target interface.

Object and class adapters

Now despite having defined the pattern, we haven’t told you the whole story yet. There are actually two kinds of adapters: object adapters and class adapters. This chapter has covered object adapters and the class diagram on the previous page is a diagram of an object adapter.

So what’s a class adapter and why haven’t we told you about it? Because you need multiple inheritance to implement it, which isn’t possible in Java. But, that doesn’t mean you might not encounter a need for class adapters down the road when using your favorite multiple inheritance language! Let’s look at the class diagram for multiple inheritance.

image with no caption

Look familiar? That’s right—the only difference is that with class adapter we subclass the Target and the Adaptee, while with object adapter we use composition to pass requests to an Adaptee.

Brain Power

Object adapters and class adapters use two different means of adapting the adaptee (composition versus inheritance). How do these implementation differences affect the flexibility of the adapter?

Real-world adapters

Let’s take a look at the use of a simple Adapter in the real world (something more serious than Ducks at least)...

Old-world Enumerators

If you’ve been around Java for a while you probably remember that the early collection 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.

image with no caption

New-world Iterators

The newer Collection classes use 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.

image with no caption

And today...

We are often faced with legacy code that exposes the Enumeration interface, yet we’d like for our new code to use only Iterators. It looks like we need to build an adapter.

Adapting an Enumeration to an Iterator

First we’ll look at the two interfaces to figure out how the methods map from one to the other. In other words, we’ll figure out what to call on the adaptee when the client invokes a method on the target.

image with no caption

Designing the Adapter

Here’s what the classes should look like: we need an adapter that implements the Target interface and that is composed with an adaptee. The hasNext() and next() methods are going to be straightforward to map from target to adaptee: we just pass them right through. But what do you do about remove()? Think about it for a moment (and we’ll deal with it on the next page). For now, here’s the class diagram:

image with no caption

Dealing with the remove() method

Well, we know Enumeration just doesn’t support remove. It’s a “read only” interface. There’s no way to implement a fully functioning remove() method on the adapter. The best we can do is throw a runtime exception. Luckily, the designers of the Iterator interface foresaw this need and defined the remove() method so that it supports an UnsupportedOperationException.

This is a case where the adapter isn’t perfect; clients will have to watch out for potential exceptions, but as long as the client is careful and the adapter is well documented this is a perfectly reasonable solution.

Writing the EnumerationIterator adapter

Here’s simple but effective code for all those legacy classes still producing Enumerations:

image with no caption

Brain Power

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?

And now for something different...

There’s another pattern in this chapter.

You’ve seen how the Adapter Pattern converts the interface of a class into one that a client is expecting. You also know we achieve this in Java by wrapping the object that has an incompatible interface with an object that implements the correct one.

We’re going to look at a pattern now that alters an interface, but for a different reason: to simplify the interface. It’s aptly named the Facade Pattern because this pattern hides all the complexity of one or more classes behind a clean, well-lit facade.

Home Sweet Home Theater

Before we dive into the details of the Facade Pattern, let’s take a look at a growing national obsession: building your own home theater.

You’ve done your research and you’ve assembled a killer system complete with a DVD player, a projection video system, an automated screen, surround sound, and even a popcorn popper.

image with no caption

Check out all the components you’ve put together:

image with no caption

You’ve spent weeks running wire, mounting the projector, making all the connections, and fine tuning. Now it’s time to put it all in motion and enjoy a movie...

Watching a movie (the hard way)

Pick out a DVD, relax, and get ready for movie magic. Oh, there’s just one thing—to watch the movie, you need to perform a few tasks:

  • ① Turn on the popcorn popper

  • ② Start the popper popping

  • ③ Dim the lights

  • ④ Put the screen down

  • ⑤ Turn the projector on

  • ⑥ Set the projector input to DVD

  • ⑦ Put the projector on wide-screen mode

  • ⑧ Turn the sound amplifier on

  • ⑨ Set the amplifier to DVD input

  • ⑩ Set the amplifier to surround sound

  • ⑪ Set the amplifier volume to medium (5)

  • ⑫ Turn the DVD player on

  • ⑬ Start the DVD player playing

image with no caption

Let’s check out those same tasks in terms of the classes and the method calls needed to perform them:

image with no caption

But there’s more...

  • When the movie is over, how do you turn everything off? Wouldn’t you have to do all of this over again, in reverse?

  • Wouldn’t it be as complex to listen to a CD or the radio?

  • If you decide to upgrade your system, you’re probably going to have to learn a slightly different procedure.

So what to do? The complexity of using your home theater is becoming apparent!

Let’s see how the Facade Pattern can get us out of this mess so we can enjoy the movie...

Lights, Camera, Facade!

A Facade is just what you need: with the Facade Pattern you can take a complex subsystem and make it easier to use by implementing a Facade class that provides one, more reasonable interface. Don’t worry; if you need the power of the complex subsystem, it’s still there for you to use, but if all you need is a straightforward interface, the Facade is there for you.

Let’s take a look at how the Facade operates:

image with no caption

A facade not only simplifies an interface, it decouples a client from a subsystem of components.

Facades and adapters may wrap multiple classes, but a facade’s intent is to simplify, while an adapter’s is to convert the interface to something different.

Constructing your home theater facade

Let’s step through the construction of the HomeTheaterFacade. The first step is to use composition so that the facade has access to all the components of the subsystem:

image with no caption

Implementing the simplified interface

Now it’s time to bring the components of the subsystem together into a unified interface. Let’s implement the watchMovie() and endMovie() methods:

image with no caption

Brain Power

Think about the facades you’ve encountered in the Java API. Where would you like to have a few new ones?

Time to watch a movie (the easy way)

It’s SHOWTIME!

image with no caption
image with no caption
image with no caption

Facade Pattern defined

To use the Facade Pattern, we create a class that simplifies and unifies a set of more complex classes that belong to some subsystem. Unlike a lot of patterns, Facade is fairly straightforward; there are no mind-bending abstractions to get your head around. But that doesn’t make it any less powerful: the Facade Pattern allows us to avoid tight coupling between clients and subsystems, and, as you will see shortly, also helps us adhere to a new object-oriented principle.

Before we introduce that new principle, let’s take a look at the official definition of the pattern:

Note

The Facade Pattern provides a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.

There isn’t a lot here that you don’t already know, but one of the most important things to remember about a pattern is its intent. This definition tells us loud and clear that the purpose of the facade is to make a subsystem easier to use through a simplified interface. You can see this in the pattern’s class diagram:

image with no caption

That’s it; you’ve got another pattern under your belt! Now, it’s time for that new OO principle. Watch out, this one can challenge some assumptions!

The Principle of Least Knowledge

The Principle of Least Knowledge guides us to reduce the interactions between objects to just a few close “friends.” The principle is usually stated as:

Design Principle

Principle of Least Knowledge: talk only to your immediate friends.

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. When you build a lot of dependencies between many classes, you are building a fragile system that will be costly to maintain and complex for others to understand.

Brain Power

How many classes is this code coupled to?

public float getTemp() {
    return station.getThermometer().getTemperature();
}

How NOT to Win Friends and Influence Objects

Okay, but how do you keep from doing this? 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:

  • The object itself

  • Objects passed in as a parameter to the method

  • Any object the method creates or instantiates

    Note

    Notice that these guidelines tell us not to call methods on objects that were returned from calling other methods!!

  • Any components of the object

    Note

    Think of a “component” as any object that is referenced by an instance variable. In other words, think of this as a HAS-A relationship.

This sounds kind of stringent doesn’t it? What’s the harm in calling the method of an object we get back from another call? Well, if we were to do that, then we’d be making a request of another object’s subpart (and increasing the number of objects we directly know). In such cases, the principle forces us to ask the object to make the request for us; that way we don’t have to know about its component objects (and we keep our circle of friends small). For example:

image with no caption

Keeping your method calls in bounds...

Here’s a Car class that demonstrates all the ways you can call methods and still adhere to the Principle of Least Knowledge:

image with no caption

Brain Power

Q:

Can you think of a common use of Java that violates the Principle of Least Knowledge?

Should you care?

A:

Answer: How about System.out.println()?

The Facade and the Principle of Least Knowledge

image with no caption

Tools for your Design Toolbox

Your toolbox is starting to get heavy! In this chapter we’ve added a couple of patterns that allow us to alter interfaces and reduce coupling between clients and the systems they use.

image with no caption
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.174.216