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.
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.
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.
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
inNamespace 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
.
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.)
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:
// Compile the library csc /t:library /out:FacadeLib.dll Facade-Library.cs // Compile the main program csc /r:FacadeLib.dll Facade-Main.cs
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.
Example 4-5. Façade pattern theory code
using System;
// Facade Pattern Judith Bishop Dec 2006
// Sets up a library of three systems, accessed through a
// Facade of two operations
// Compile with
// csc /t:library /out:FacadeLib.dll Facade-Library.cs
namespace Library {
internal class SubsystemA {
internal string A1( ) {
return "Subsystem A, Method A1\n";
}
internal string A2( ) {
return "Subsystem A, Method A2\n";
}
}
internal class SubsystemB {
internal string B1( ) {
return "Subsystem B, Method B1\n";
}
}
internal class SubsystemC {
internal string C1( ) {
return "Subsystem C, Method C1\n";
}
}
}
public static class Facade {
static SubsystemA a = new SubsystemA( );
static SubsystemB b = new SubsystemB( );
static SubsystemC c = new SubsystemC( );
public static void Operation1( ) {
Console.WriteLine("Operation 1\n" +
a.A1( ) +
a.A2( ) +
b.B1( ));
}
public static void Operation2( ) {
Console.WriteLine("Operation 2\n" +
b.B1( ) +
c.C1( ));
}
}
// ============= Different compilation
using System;
using FacadeLib;
// Compile with csc /r:FacadeLib.dll Facade-Main.cs
class Client {
static void Main ( ) {
Facade.Operation1( );
Facade.Operation2( );
}
}/* Output
Operation 1
Subsystem A, Method A1
Subsystem A, Method A2
Subsystem B, Method B1
Operation 2
Subsystem B, Method B1
Subsystem C, Method C1
*/
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:
SubsystemC x = new SubsystemC( );
x.C1( );Facade2Main.cs(12,3): error CS0122: 'FacadeLib.SubsystemC' is inaccessible
due to its protection level
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 theinternal
modifiers topublic
, which will make the façade optional, or transparent. That is, as well as being able to go through theFacade
, the client will be able to instantiateSubsystemA
directly, for example, and then callA1
.- 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:
public void ClientMain ( ) { Facade.Operation1( ); Facade.Operation2( ); }
This implies that
Facade
is a static class. No instantiation is necessary; the user interfaces with theFacade
class directly. In fact, the Singleton pattern (Chapter 5) would be the preferred way of achieving this effect.
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:
Find album AddSet setname AddPhoto photoname1 AddPhoto photoname2 ... Display
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.)
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:
|
But consider using instead:
|
Choose the Façade you need...
|
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.
Get C# 3.0 Design Patterns now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.