Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training,
learning paths, books, tutorials, and more.

Chapter 4. Structural Patterns: Adapter and Façade

The main pattern we will consider in this chapter is the Adapter
pattern. It is a versatile pattern that joins together types that were not
designed to work with each other. It is one of those patterns that comes
in useful when dealing with legacy code—i.e., code that was written a
while ago and to which one might not have access. There are different
kinds of adapters, including class, object, two-way, and pluggable. We’ll
explore the differences here. The second pattern we will look at in this
chapter—the Façade pattern—is a simple one that rounds out the structural
group. The aim of this pattern is to provide a simplified interface to a
set of complex systems.

Adapter Pattern

Role

The Adapter pattern enables a system to use classes whose
interfaces don’t quite match its requirements. It is especially useful
for off-the-shelf code, for toolkits, and for libraries. Many examples
of the Adapter pattern involve input/output because that is one domain
that is constantly changing. For example, programs written in the
1980s will have very different user interfaces from those written in
the 2000s. Being able to adapt those parts of the system to new
hardware facilities would be much more cost effective than rewriting
them.

Toolkits also need adapters. Although they are designed for
reuse, not all applications will want to use the interfaces that
toolkits provide; some might prefer to stick to a well-known,
domain-specific interface. In such cases, the adapter can accept calls
from the application and transform them into calls on toolkit
methods.

Illustration

Our illustration of the Adapter pattern is a very real one—it
involves hardware instruction sets, not input/output. From 1996 to
2006, Apple Macintosh computers ran on the PowerPC processor. The
operating system was Mac OS X. But in April 2006, Apple started
releasing all new Apple computers—iMacs, Minis, and MacBooks—with
Intel Core Duo processors. Mac OS X was rewritten to target the new
processor, and users of the new computers mostly accessed existing
Intel-based software via other operating systems, such as Linux and
Windows. Figure 4-1
shows iMacs made in 1998 and 2006.

Mac OS X was originally designed to take advantage of the
AltiVec floating-point and integer SIMD instruction set that is part
of the PowerPC processor. When the Intel processor replaced this
processor, calls to AltiVec instructions from Mac OS X had to be
retargeted to the Intel x86 SSE extensions, which provide similar
functionality to AltiVec.

For something as important as an operating system, the code
could be rewritten to replace the calls to AltiVec with calls to SSE.
However, Apple recognized that application developers might not want
to do this, or might not have access to the source of old
AltiVec-based code, so they recommended the use of the
Accelerate framework. The Accelerate framework is
a set of high-performance vector-accelerated libraries. It provides a
layer of abstraction for accessing vector-based code without needing
to use vector instructions or knowing the architecture of the target
machine. (This is the important point for us here.) The framework
automatically invokes the appropriate instruction set, be it PowerPC
or Intel (in these processors’ various versions).

Thus, the Accelerate framework is an example of the Adapter
pattern. It takes an existing situation and adapts it to a new one,
thus solving the problem of migrating existing code to a new
environment. No alterations to the original code are
required.[3]

Design

The Adapter pattern’s important contribution is that it promotes
programming to interfaces. The Client works to a domain-specific standard,
which is specified in the ITarget
interface. An Adaptee class
provides the required functionality, but with a different interface.
The Adapter implements the ITarget interface and routes calls from the
Client through to the Adaptee, making whatever changes to
parameters and return types are necessary to meet the requirements. A
Target class that implements the
ITarget interface directly could
exist, but this is not a necessary part of the pattern. In any case,
the Client is aware only of the
ITarget interface, and it relies on
that for its correct operation.

The adapter shown in Figure 4-2 is a class
adapter because it implements an
interface and inherits a class. The alternative
to inheriting a class is to aggregate the
Adaptee. This creates an
object adapter. The design differences are
primarily that overridingAdaptee behavior can be done more easily
with a class adapter, whereas adding behavior to
Adaptees can be done more easily
with an object adapter. As we go along, I will point out different
instances.

Figure 4-2. Adapter pattern UML diagram

The purpose of the ITarget
interface is to enable objects of adaptee types to be interchangeable
with any other objects that might implement the same interface.
However, the adaptees might not conform to the operation names and
signatures of ITarget, so an
interface alone is not a sufficiently powerful mechanism. That is why
we need the Adapter pattern. An Adaptee offers similar functionality to
Request, but under a different name
and with possibly different parameters. The Adaptee is completely independent of the
other classes and is oblivious to any naming conventions or signatures
that they have. Now, let’s consider the roles in the pattern:

ITarget

The interface that the Client wants to use

Adaptee

An implementation that needs adapting

Adapter

The class that implements the ITarget interface in terms of the
Adaptee

Request

An operation that the Client wants

SpecificRequest

The implementation of Request’s functionality in the
Adaptee

Tip

The pattern applies to a single computer, which would only
have either the PowerPC or the Intel chip. In this case, it has the
Intel chip—hence the need for the adapter. There is no Target class present, just the ITarget interface.

To test whether you understand the Adapter pattern, cover the
lefthand column of the table below and see if you can identify its
players among the items from the illustrative example (Figure 4-1), as shown in
the righthand column. Then check your answers against the lefthand
column.

Client

Mac OS X (or any Mac application)

ITarget

The specification of the AltiVec instruction set

Request

A call to an AltiVec instruction

Adapter

The Accelerate framework

Adaptee

An Intel processor with an SSE instruction set

SpecificRequest

A Call to an SSE instruction

Implementation

It is best to illustrate the structure of the adapter with a
small example, even at the theory code level. Suppose that technical
readings are being collected and reported at a high level of
precision, but the client can only make use of rough estimates. The
signatures for the interface would be couched in terms of integers,
and for the actual implementation in terms of double-precision
numbers. Thus, an adapter is needed, as shown in Example 4-1.

The main program in the client shows two scenarios. First, there
is an example of how the Adaptee
could be called directly (line 33)—its output is shown in line 43.
However, the client wants to work to a different interface for
requests (lines 17 and 38). The Adapter implements the ITarget interface and inherits the Adaptee (line 21). Therefore, it can accept
Request calls with a string-int signature and route them to the
Adaptee with a double-double-double
signature (line 23). The new output is shown on line 46.

A feature of adapters is that they can insert additional
behavior between the ITarget
interface and the Adaptee. In other
words, they do not have to be invisible to the Client. In this case, the Adapter adds the words "Rough estimate is" to indicate that the
Request has been adapted before it
calls the SpecificRequest (line
23).

Adapters can put in varying amounts of work to adapt an Adaptee’s implementation to the Target’s interface. The simplest adaptation
is just to reroute a method call to one of a different name, as in the
preceding example. However, it may be necessary to support a
completely different set of operations. For example, the Accelerate framework mentioned in the "Illustration" section will need to do considerable work
to convert AltiVec instructions to those of the Intel Core Duo
processor. To summarize, we have the following options when matching
adapter and adaptee interfaces:

Adapter interface and adaptee interface have same
signature

This is the trivial case, with not much work to do.

Tip

Many examples of the Adapter pattern operate at this
level and are not illustrative or helpful in explaining its
real power. Beware of them.

Adapter interface has fewer parameters than
adaptee interface

The adapter calls the adaptee with some dummy
input.

Tip

This case is shown in Example 4-1, where the second
parameter is defaulted to 3.

Adapter interface has more parameters than adaptee
interface

The adapter adds the missing functionality, making it half
an adapter and half a component in its own right.

Adapter interface has other types than adaptee
interface

The adapter performs some type conversion
(casting).

Tip

This case is shown in Example 4-1, where the first
double parameter is created
from an integer and the double return type is cast back to a
string.

Of course, combinations of these basic cases are also
possible.

Two-Way Adapters

Adapters provide access to some behavior in the Adaptee (the behavior required in the
ITarget interface), but Adapter objects are not interchangeable with
Adaptee objects. They cannot be
used where Adaptee objects can
because they work on the implementation of the Adaptee, not its interface. Sometimes we
need to have objects that can be transparently ITarget or Adaptee objects. This could be easily
achieved if the Adapter inherited
both from both classes; however, such multiple inheritance is not
possible in C#, so we must look at other solutions.

The two-way adapter addresses the problem of two systems where
the characteristics of one system have to be used in the other, and
vice versa. An Adapter class is set
up to absorb the important common methods of both and to provide
adaptations to both. The resulting adapter objects will be acceptable
to both sides. Theoretically, this idea can be extended to more than
two systems, so we can have multiway adapters, but there are some
implementation limitations: without multiple inheritance, we have to
insert an interface between each original class and the
adapter.

Our Macintosh example has a follow-up that illustrates this
point nicely. With an Intel processor on board, a Mac can run the
Windows operating system.[4] Windows, of course, is targeted directly for the Intel
processor and will make use of its SSE instructions where necessary.
In such a situation, we can view Windows and Mac OS X as two clients
wanting to get access to the Adaptee (the Intel processor). The Adapter catches both types of instruction
calls and translates them if required. For an instruction issued by an
application, the situation on the different operating systems running
on a Mac with an Intel processor can be summed up using pseudocode as
follows:

A key point with a two-way adapter is that it can be used in
place of both ITarget and the
Adaptee. When called to execute
AltiVec instructions, the adapter behaves as a PowerPC processor (the
Target), and when called to execute
SSE instructions, it behaves as an Intel processor (the Adaptee).

Example: The Seabird

We have already looked at some theory code and discussed an
interesting application of the Adapter pattern concept. It is now time
for an example. That illustrates a two-way adapter but sticks closely
to the structure of Example 4-1.

Suppose an inventor has an embedded control system for a
revolutionary water plane called the Seabird. The
plane derives from both aircraft and seacraft design: specifically,
the Seabird has the body of a plane but the controls and engine of a
ship. Both parts are being assembled as-is. The inventor of the
Seabird is adapting as much as he can so that it is possible to
control the craft via the interfaces provided by both parts.

In pattern terms, the Seabird
will be a two-way adapter between the Aircraft and Seacraft classes. When running the
experiments on the Seabird, the
inventor will use an adapter and will be able to access methods and
data in both classes. In other words, Seabird will behave as both an
Aircraft and a Seacraft. We could get a simple adapter to
behave as an Aircraft, say, and use
the features of a Seacraft, but we
could not do this the other way as well. With a two-way adapter,
however, this is possible.

The ITarget interface,
IAircraft, has two properties,
Airborne and Height, and one method, TakeOff. The Aircraft class implements the interface in
the manner of an aircraft. The IAdaptee interface, ISeacraft (new in this version of the
pattern), has two methods—Speed and
IncreaseRevs—that are implemented
by the Seacraft class. The Adapter inherits from the Adaptee (Seacraft) and implements the ITarget (IAircraft) in the normal way. The adapter
then has to do some work to match these two different interfaces to
each other. Table 4-1
makes it easier to see how one would approach such an adapter.

Table 4-1. Adapter pattern Seabird example—methods and
properties

Aircraft
(Target)

Seacraft
(Adaptee)

Seabird
(Adapter)

Experiment
(Client)

Inherits Seabird, implements Aircraft

Instantiates seabird

Methods

TakeOff—sets Airborne and Height to 200

TakeOff—involves Seacraft, IsFlying, and IncreaseRevs

seabird.TakeOff—goes to Seabird

IncreaseRevs—changes speed by
10

IncreaseRevs—calls Seacraft IncreaseRevs and SeacraftIsFlying and sets the
height

(seabird as ISeacraft) IncreaseRevs—goes to Seabird

Variables

Airborne—is true after takeoff

Airborne—is true if Height > 50

seabird.Airborne—goes to Seabird

Speed—returns the
speed

(seabird as Seacraft) Speed—goes to Seacraft

Height—returns the
height

Height—returns the stored
height

seabird.Height—goes to Seabird

The classes representing each part of the invention offer
different methods: TakeOff for an
aircraft and IncreaseRevs for a
seacraft. In the simple adapter, only TakeOff would work. In the two-way adapter,
we also capture the method from the Adaptee (IncreaseRevs) and adapt it to include
information that otherwise would be supplied by the Target (the height, here).

Two-way adapters also handle variables—in this case, Airborne, Speed, and Height. Those from the Aircraft (the Target) are trapped and adapted to return
locally held information. The one in the Seacraft (Adaptee) is routed through.

The result of all of the above, when translated into C# classes,
is that the Client can conduct
experiments on the Seabird as follows:

The calls to seabird.Airborne
and seabird.Height (lines 4 and 6)
are regular adapter methods that adapt as described in Table 4-1. However, the
ability to treat the Seabird as a Seacraft as well (lines 2, 3, and 7) is
peculiar to the two-way adapter. The full program is given in Example 4-2.

Pluggable Adapters

Developers who recognize that their systems will need to work
with other components can increase their chances of adaptation.
Identifying in advance the parts of the system that might change makes
it easier to plug in adapters for a variety of new situations. Keeping
down the size of an interface also increases the opportunities for new
systems to be plugged in. Although not technically different from
ordinary adapters, this feature of small interfaces gives them the
name pluggable adapters.

A distinguishing feature of pluggable adapters is that the name
of a method called by the client and that existing in the ITarget interface can be different. The
adapter must be able to handle the name change. In the previous
adapter variations, this was true for all Adaptee methods, but the client had to use
the names in the ITarget interface.
Suppose the client wants to use its own names, or that there is more
than one client and they have different terminologies. To achieve
these name changes in a very dynamic way, we can use delegates (see
later sidebar).

Now, consider Example 4-3, which shows how to
write pluggable adapters with delegates.

The delegate is contained in the Adapter and is instantiated on line 24, from
one of the standard generic delegates. On lines 33 and 40, it is
assigned to the methods Precise and
Estimate, which are in the Adaptee and Target, respectively. Lines 31–34 show the
use of an anonymous function to augment the results from the Adaptee. Notice that the Client (the Main method) refers only to its chosen
method name, Request (see
sidebar).

The pluggable adapter sorts out which object is being plugged in
at the time. Once a service has been plugged in and its methods have
been assigned to the delegate objects, the association lasts until
another set of methods is assigned. What characterizes a pluggable
adapter is that it will have constructors for each of the types that
it adapts. In each of them, it does the delegate assignments (one, or
more than one if there are further methods for rerouting).

C# Feature—Delegates

A method that is specified in an interface is implemented with
the same name in the base class. However, such close coupling is not
always appropriate. The delegate construct can be used to break the
coupling for this purpose. A delegate is a type
that defines a method signature. A delegate
instance is then able to accept a method of that
signature, regardless of its method name or the type that
encapsulates it.

The delegate syntax in C# evolved considerably from Versions
1.0 to 2.0 to 3.0. We shall concentrate on the 3.0 version, which is
the simplest to code. The language has predefined standard
generic delegate types, as follows:

where R is the return type
and the As and as represent the argument types and names,
respectively. There is also another set of generic delegates
introduced with the name Action that represent
methods that do not return a value. Thus, declaring a delegate
instance is now straightforward. For example, we can define a
Request delegate that takes an
integer parameter and returns a string:

public Func <int,string>
Request;

Next, we can assign an actual method to Request, as in:

Request =
Target.Estimate;

The delegate can then be invoked just as any other method
would be:

string s =
Request(5);

This statement would invoke the Estimate method in the Target class, returning a string.

Example: CoolBook

Our last Adapter pattern example picks up on an earlier example
that we explored with the Proxy and Bridge patterns: SpaceBook. Recall
that Example 2-4 introduced
the SpaceBook class and its
authentication frontend, MySpaceBook. Then, Example 2-6 showed how we could
create a Bridge to an alternative
version of MySpaceBook called
MyOpenBook, which did not have
authentication. Now, we are going to consider going GUI. The input and
output of SpaceBook (wall writing,
pokes, etc.) will be done via Windows forms. There will be a separate
form for each user, and users will be able to write on each other’s
pages as before. However, now the input will be interactive, as well
as being simulated by method calls in the program. Thus, we will have
a prototype of a much more realistic system.

C# Feature—Anonymous Functions

Anonymous functions simplify the creation
of one-time behavior for delegates. They are useful when additional
behavior is to be added before or after a method is invoked. For
example:

Here, the method to be invoked is Precise. The parameters are different from
the ones in the delegate, as is the return value. The anonymous
function can wrap up the changes and assign a “complete solution” to
the delegate for later invocation.

Creating a GUI and handling its events is a specialized
function, and it is best to isolate it as much as possible from the
ordinary logic of the system. In setting up CoolBook, we wrote a
minimal GUI system called Interact.
All Interact does is set up a
window with a TextBox and a
Button called “Poke,” and pass any
click events on the Button to a
delegate (see sidebar). Separately from this, we wrote MyCoolBook, which mimics the functionality
of MyOpenBook and, for reasons of
simplicity at this stage, maintains its own community of users. Given
the following client program, the output will be as shown in Figure 4-3.

The second “Tom : Poked you” was created interactively by Tom
typing in “Judith” on his wall, selecting it, and clicking the Poke
button. Judith then wrote on her own wall, and was getting ready to
poke Tom when the snapshot was taken.

MyCoolBook builds on top of
Interact and acts as the adapter
class. As can be seen in the Client, MyOpenBook and MySpaceBook have been completely plugged out
and replaced by MyCoolBook. We can
just change the instantiations back, and everything will revert to the
old system. This is what a pluggable adapter achieves. Consider the
insides of the adapter in Example 4-4. It inherits from
MyOpenBook and, through
inheritance, it makes use of the MySpaceBook object stored there, as well as
the Name property. It reimplements
the three important methods—Poke
and the two Add methods—and has two
methods that connect it to Interact
via a form object called visuals.

Of the three reimplemented methods, only the behavior of the
first Add is specific to MyCoolBook. The other two methods are very
much like those in MyOpenBook.
However, the problem is that given the closed nature of SpaceBook, MyCoolBook cannot access the dictionary
there and has to keep its own community. This sometimes happens with
adapters. If it were possible to rewrite parts of the Target in a more collaborative way, the
adapter could do less work. This idea is addressed in the upcoming
"Exercises" section. The code for the full CoolBook system is shown in the
Appendix.

One point to note is the anonymous function that is passed to
the Thread class in the CoolBook constructor. This is a very quick
way of creating an object in a new thread. The last statement is
Application.Run( ), which starts
drawing the form and opens up a message “pump” for the interactive
input/output on it. Finally, Start
is called on the thread.

C# Feature—Events

Delegates are used extensively in Windows GUI event-driven
programming, where they reflect the need to call back into the
user’s code when some event happens. Mostly,
existing code of this type will use an older syntax. Also, because
the new Func delegates must have
return types, void delegates must
use the original syntax too. Consider a simple example of wanting to
inform one object that input has occurred in another object (this is
part of Example 4-4).
We first declare a delegate visible to both classes:

Then, in the class where the event is handled, we create an
instance of the delegate and add it to the event object of the class
that will receive the event. When creating the delegate, we indicate
the method that it will call (in this case, OnInput):

The action of invoking the InputEvent delegate causes the method
currently assigned to it (here, OnInput) to be invoked. Thus, the callback
from one class to the other is achieved.

More than one method can be associated with a delegate; when
such a delegate is invoked, all its methods are called. Thus, if
another object needed to know about input in the preceding example,
it could add its own handler method on to InputEvent using +=. Event handlers can be removed using
-=.

Use

The Adapter pattern is found wherever there is code to be
wrapped up and redirected to a different implementation. In 2002,
Nigel Horspool and I developed a system called
Views that enabled an XML specification of a
Windows GUI to run on the cross-platform version of Windows called
Rotor. The Views engine ran with the GUI program and adapted Views
method calls to Windows calls. That benefited the clients (students)
because they could use a simpler interface to GUI programming. A
subsequent advantage was that Vista, the successor to Windows XP, used
the same approach.

At the time, it was a long way around to get Windows forms, but
the adaptation paid off later. In 2004, the backend of the Views
engine was ported by Basil Worrall to QT4, a graphics toolkit running
on Linux. Immediately, all applications that were using Views for GUI
programming became independent of Windows and could run with the Mono
.NET Framework on Linux. The Views engine was therefore a pluggable
adapter. (Our paper describing the approach is referenced in the
Bibliography at the end of the book.)

Use the Adapter
pattern when...

You have:

A domain-specific interface.

A class to connect to with a mismatching
interface.

You want to:

Create a reusable class to cooperate with
yet-to-be-built classes.

Change the names of methods as called and as
implemented.

Support different sets of methods for different
purposes.

Choose the Adapter you need...

Class adapter

Simple and versatile, invisible to the
client.

Object adapter

Extensible to subclasses of the adapter.

Two-way adapter

Enables different clients to view an object
differently.

Pluggable adapter

Presence of adapter is transparent; it can be
put in and taken out

Several adapters can be active.

Exercises

Consider the Seabird program. Would it be possible to
instantiate an Aircraft object
instead of a Seacraft object
and change the methods inside Seabird accordingly? If so, make the
changes. If not, explain how the present program would need to be
altered to enable this and then make the changes.

Add a “SuperPoke” button to CoolBook, enabling one user to
send a message to another.

Having two different communities for SpaceBook and CoolBook
is clearly a disadvantage. Assume you can make minor changes to
the SpaceBook, MySpaceBook, and MyOpenBook classes, and see whether you
can remove the community collection from MyCoolBook, routing all accesses back
through MyOpenBook to SpaceBook.

Façade Pattern

Role

The role of the Façade pattern is to provide different
high-level views of subsystems whose details are hidden from users. In
general, the operations that might be desirable from a user’s
perspective could be made up of different selections of parts of the
subsystems.

Illustration

Simple interfaces to complex subsystems abound in real life.
They can be created to make frequent use of a system faster, or to
differentiate between novices and power users. A good illustration is
Amazon.com’s 1-Click® system (Figure 4-4), which simplifies the
process of ordering items for well-known customers. Normally, after
selecting an item to purchase, an Amazon customer has to enter
delivery and bank account details before the order is accepted. If
these details are stored and the customer verifies her identity in
some way, 1-Click takes that customer straight to the checkout. The
customer’s stored bank account details and selected delivery address
are used for the purchase, thus considerably speeding up (and
simplifying) the ordering process. Thus, the 1-Click option forms a
façade to the fuller system underneath.

Figure 4-4. Façade pattern illustration—1-Click®

Design

Hiding detail is a key programming concept. What makes the
Façade pattern different from, say, the Decorator or Adapter patterns
is that the interface it builds up can be entirely new. It is not
coupled to existing requirements, nor must it conform to existing
interfaces. There can also be several façades built up around an
existing set of subsystems. The term “subsystem” is used here
deliberately; we are talking at a higher level than classes. See the
UML diagram in Figure 4-5; it
considers the subsystems to be grouped together, so they can interact
in agreed ways to form the top-level operations.

Figure 4-5. Façade pattern UML diagram

The roles are:

Namespace 1

A library of subsystems

Subsystem

A class offering detailed operations

Façade

A class offering a few high-level operations as selections
from the subsystems

Namespace 2

Where the client resides

Client

Calls the high-level operations in the Façade in Namespace 1

As shown in the UML diagram, the client’s code does not make
reference to the classes of the names of the subsystems; it only gets
access to their operations via the Façade.

Implementation

The Façade pattern is simple to implement. It uses the C#
concept of namespaces. Classes in namespaces have the facility to
define accessibility as internal or
public. If accessibility is defined
as internal, the member is visible
only in the assembly in which the namespace is compiled. In a very
large system, the client’s GUI will be in a different namespace from
the library, so we can enforce the Façade. (Alternative
implementations of the Façade pattern will be discussed
shortly.)

QUIZ: Match the Façade Pattern Players with the 1-Click
Illustration

To test whether you understand the Façade pattern, cover the
lefthand column of the table below and see if you can identify its
players among the items from the illustrative example (Figure 4-4), as shown in the
righthand column. Then check your answers against the lefthand
column.

In Example 4-5, the theory code
comes from two files: Façade-Main.cs and Façade-Library.cs. Both have to be compiled
with special directives so that library in Façade-Library.cs is recognized as a
lib file and the client in
Façade-Main.cs can reference it.
These commands are:

Tip

This process of compiling and using libraries is facilitated
in environments such as Visual Studio.

The example mirrors the diagram in Figure 4-5. Three subsystems, implemented
as classes, are inserted into the library. Facade is a static class that instantiates
the three subsystems under the façade as objects called a, b, and
c. Operations 1 and 2
then select combinations of methods from a, b, and
c. For example, Operation1 will call two methods in a, one in b, and none in c. Thus, the Facade is a means of providing an interface
to operations that should, on their own, remain hidden.

The client starts with a using statement that indicates it wants
access to the public members in the FacadeLib namespace. Then it calls the
Facade’s two high-level operations.
The output is shown below in Example 4-5.

Everything in the façade has to be public so that the Client, which is compiled into a different
assembly, can access it. The classes all have the default internal visibility, limiting access to them
to the assembly in which they were compiled
(excluding the Client). As a test, if we try to let the
Client instantiate any of the
subsystems directly, we will get an error like the
following:

Façade Alternatives

Some alternative implementations of the Façade pattern
are:

Transparent façades

The façade described in the preceding example is
opaque, in that the subsystems cannot be
accessed except via the Facade object. This requirement might
be too stringent. Suppose some users want to get at the
individual operations of particular subsystems. We can change
all the internal modifiers to
public, which will make the
façade optional, or transparent. That is,
as well as being able to go through the Facade, the client will be able to
instantiate SubsystemA
directly, for example, and then call A1.

Static façades

In most cases, there will only be one instance of a façade
in the client for a set of subsystems, so its operations could
more appropriately be called on the user’s side as members of
the class itself, as in:

This implies that Facade is a static class. No
instantiation is necessary; the user interfaces with the
Facade class directly. In
fact, the Singleton pattern (Chapter 5) would be the
preferred way of achieving this effect.

Example: Novice Photo Library

Consider the Composite pattern example in Chapter 3 that showed how
photos could be loaded into directories of arbitrary configurations.
The instructions for using the six commands relied on the current
place (“where I am”), which was a powerful, but perhaps confusing,
concept. For novices, it might be a good idea to abstract from the
power of the Photo Library and just let them load sets of photos, all
at the same level, and immediately display them (as Flickr does). The
commands could simply be:

Upload setname
photoname1 photoname2 ...

ending with a blank line or some other indicator. These
instructions would translate into the following existing ones:

Instead of going in and altering the code to have a new command,
we can have a completely separate Façade that makes the calls as
described above. The more complex and rich commands might be available
to expert users, but not to novices. (See the preceding discussion on
opaque and transparent façades.)

Use

Façades can be useful in different circumstances. There are many
instances where a computer system is built up out of a set of largely
independent subsystems. One well-known case is a compiler: it consists
of clearly identifiable subsystems called a lexical analyzer, a syntax
analyzer, semantic analyzers, a code generator, and several
optimizers. In modern compilers, each subsystem has many subtasks. The
different tasks and subtasks are called in a sequence, but sometimes
they are not all needed. For example, if an error occurs in one of the
analysis tasks, the compiler might not go onto a later phase. (The
.NET compilers follow this approach.) Hiding this detail behind a
façade enables a program to call tasks within subsystems in a logical
order, passing the necessary data structures between them.

Use the Façade
pattern when...

A system has several identifiable subsystems
and:

The abstractions and implementations of a
subsystem are tightly coupled.

The system evolves and gets more complex, but
early adopters might want to retain their simple
views.

The Abstract Factory pattern for designs where
subsystems create objects on behalf of the
client.

Choose the Façade you need...

Opaque

Subsystem operations can only be called through
the Façade.

Transparent

Subsystem operations can be called directly as
well as through the Façade.

Singleton

Only one instance of the Façade is
meaningful.

Exercises

Program the suggested extension for novices to the Photo
Library program.

Consider large systems that you use on the Internet, and
come up with more examples of Façades.

If you have access to source code for a compiler, find the
part where the subsystems are called and examine how the data
structures are passed between them.

Pattern Comparison

The Adapter pattern has much in common with the patterns discussed
in Chapter 2. The
differences are in the intents of the patterns. A
bridge, for example, separates an interface and its implementation so
that they can vary independently, whereas an adapter changes the
interface of an existing object. The Adapter pattern is more useful for
one-off changes, whereas the Bridge pattern anticipates that change
might happen continuously.

A decorator enhances an object without changing its interface and
should be transparent to the application. An adapter is not transparent,
as it is the named implementation of the interface the client sees. The
Proxy pattern does not change any interfaces; it defines substitute
objects for other objects.

From a certain point of view, the Façade pattern is also adapting
requests: it transforms high-level requests into a sequence of
lower-level requests. The Façade’s intent is to hide complexity, and the
Façade subsystems are not intended to be accessible by the
client.

To complete the picture, we can classify the Adapter and Façade
patterns according to the mechanisms shown in Table 4-2.