Intent
Provides a unified interface to a set of
inter-related services. Simplifies use and inclusion
of the subservices.
Also Known As
Configuration
Example TinyOS Components
GenericComm, Matchbox
Motivation
Complex system components, such as a filesystem
or networking abstraction, can be implemented across
many components. Higher-level operations may be
based on lower-level ones, and a user needs access
to both. The composition can also not be vertical in
nature: high-level functionality can be spread
across several components for implementation
reasons. Although implemented separately, these
pieces of functionality are part of a cohesive whole
that needs to be presented as a logical unit.
For example, the Matchbox filing system provides
interfaces for reading, writing, and deleting files,
as well as interfaces for metadata operations such
as renaming. Each of these interfaces is implemented
in a separate module. For example, the implemention
of file writing depends on being able to read the
file, in case it needs to be relocated: the
Write component uses the Read
component in its implementation, and
Matchbox exports both.
Exporting the various interfaces in different
components can make using the abstraction more
difficult for the programmer. Instead of including a
single component, a configuration would need to
include several. Additionally, each part needs a
separate configuration, increasing clutter in the
component namespace.
The Facade pattern allows you to provide a
uniform access point to interfaces provided by many
components. A Facade is just a nesC configuration
that exports the interfaces of several underlying
components. Additionally, the Facade can wire the
underlying components to satisfy dependencies.
Applicability
Use the Facade pattern when:
- An abstraction is implemented as several
separate components.
- It is preferrable to present the abstraction
in entirety rather than in parts.
Structure
Participants
- Proxy: the component that all other
components wire to. It encapsulates the
implementation and exports its interfaces with
pass-through wiring. It has the same signature as
the Implementation component.
- Implementation: the specific version of
the component.
- Users: components that want to use the
functionality the abstraction provides.
- Service: components providing
functionality that the that abstraction depends
on.
Collaborations
Consequences
Because the Facade names all of its sub-parts,
they will all be included in the nesC component
graph. nesC's code pruning can remove components
that are not used, but if any component handles
interrupts, then code in the interrupt paths will be
included, as will any tasks that those interrupts
post. If you expect applications to only use a very
narrow part of an abstraction, then presenting it
using a Facade can be wasteful.
Implementation
Sample Code
The Matchbox filing system is a good example of a
Facade. Various file operations are all implemented
in different components, but the top-level
Matchbox configuration provides them as a
unified abstraction:
configuration Matchbox {
provides {
interface StdControl;
interface FileDelete;
interface FileDir;
interface FileRead[uint8_t fd];
interface FileRename;
interface FileWrite[uint8_t fd];
}
uses {
interface Debug;
/**
* Signaled when the filing system is ready to accept operations.
* @return Ignored.
*/
event result_t ready();
}
}
implementation {
components Read, Write, Dir, Rename, Delete;
....
FileDelete = Delete;
FileDir = Dir;
FileRead = Read;
FileRename = Rename;
FileWrite = Write;
...
}
Known Uses
Related Patterns
The Proxy pattern is similar to the Facade
in that it exports interfaces, but it does so for a
single component in order to simplify implementation
selection and namespace management. In contrast, the
Facade groups several pieces of functionality into a
logical whole. However, as a Facade can also act in
part as a Proxy, as the choice of actual
implementations of the services is constrained to
the Facade.
|