The Façade Pattern
The Facade Pattern
Contextual Forces
Motivation
Provide a simplified, improved, or more object-oriented interface to a sub-system that is overly complex (or may simply be more complex than is needed for the current use), poorly designed, a decayed legacy system, or otherwise inappropriate for the system consuming it. Façade allows for the re-use of a valuable sub-system without coupling to the specifics of its nature.
Encapsulation
The sub-system’s nature (complexity, design, decay, OO/Procedural nature, etc...). Optionally, the presence of the sub-system itself (see Questions, Concerns, Credibility checks)
Procedural Analog
When creating large procedural systems, often we will create a "gateway routine" as a sort of API that allows the aggregation of many different parts of the system into a single called routine. This "gateway" routine makes the system easier to use, and is essentially the precursor to a Façade in an object-oriented system. It it not strictly an analog, it is in fact an early version of the pattern.
Non-Software Analog
A hotel concierge (at an upscale hotel) stands between the hotel guest and all the various services that are needed to make for a successful, satisfying stay at the hotel.
The guest has goals, which are expressed from the guest's point of view. The concierge translates these goals into needed interactions with the concrete services needed to achieve them.
For example, the guest may say "we'd like to go out to an evening dinner, and a show, and they return to the hotel for an intimate dessert in our room".
The concierge handles all the nitty-gritty details (a taxi, restaurant reservations, theatre tickets, housekeeping prep of the room, the kitchen preparing the dessert, room-service delivery, etc...)
The concierge here is the Façade analog.
Implementation Forces
Example
public class Façade { public void m1() { // make all calls into the existing system, // hiding the complexity } public string m2() { // make all calls into the existing system, // converting the return return rval; } }
Questions, concerns, credibility checks
Can we totally encapsulate the sub-system? The Façade can be a convenience service or a constraining service.
Convenience:' The System Under Development can "go around" and use the existing sub-system directly for infrequent, unusual, or orthogonal needs. This keeps the interface of the Façade relatively small and cohesive, but couples the System Under Development to the sub-system. The call marked "optional" in the diagram above shows this behavior.
Constraining: The System Under Development must use the Façade for all accesses to the existing sub-system. This may broaden the interface of the Façade, and weaken its cohesion, but it makes the sub-system itself completely swappable. Because the sub-system is hereby encapsulated, we often refer to such a Façade as an “Encapsulating Façade”.
Can we make the Façade stateless? Façades are often fairly heavyweight and instantiating them can impact performance. Therefore, if they can be made stateless, they can be implemented as Singletons, which alleviates the performance and resounce impact of the Façade.
Options in implementation
Façade is often implemented using other patterns. In fact, the Façade is not really a specific design, but rather a role that is implemented in whatever way is considered most appropriate given the forces in the problem.
For example, here is a Façade implemented using a Chain of Responsibility
To keep a Façade stateless, often it is advisable to externalize the state into a lightweight object:
Legacy Conversion: Façades also can have a strong role in converting legacy systems incrementally to more modern software. The following example is one drawn from the work of Martin Fowler.
"Strangling" a Legacy System
Imagine an old, very decayed, and poorly-implemented legacy system. You've probably had to work with one or more of these in your practice. We often think of them as a "big ball of mud" because they are incomprehensible, brittle, and "dense":
Job one is to stop using the system in the old way when writing new code that has to interact with it. If we could, we'd stop here and refactor or rewrite the system entirely, but often that is simply not an option: we have to live with it, at least for now.
However, using the old system directly (as the "legacy users" do) will mean writing code that is similar in nature to the code in the system, and at the very least we want our new code to be clean, tested, and object-oriented. So, we create a Façade with the interface we "wish we had" and then delegate from there into the various routines in the legacy system. The Facade, as mentioned below, can be mocked to make our new code much more testable.
Now that we have this in place, the "new users" can be developed more cleanly and with higher quality. Now, over time, and without siginifcant time pressure on the project, we can incrementally pull out behaviors from the legacy system into more clean, tested, object-oriented code, and delegate from the old routines into the new ones:
Once we reach the point that the legacy system remains only as a series of delegation points, nothing but a thin shell around the new behaviors, we can begin to refactor the legacy users to use the Façade instead of the delegating routines in the older system. The Façade itself can also be refactored to use the new code directly. Again, this can be done incrementally, as time permits, without a lot of pressure. Naturally, once all the legacy users and the Façade no longer use the thin-shell legacy system, it can be retired.
Consequent Forces
Testing issues
Façades are inherently difficult to test if (as is common) the sub-systems they cover are hard to test. However, the presense of the Façade makes the System Under Development fundamentally easier to test because the Façade, once in place, can be Mocked to eliminate unpredictable dependencies.
Cost-Benefit (gain-loss)
A Façade keeps the client system clean, reduces complexity when accessing existing sub-systems, and can allow for the re-use of valuable legacy systems in a new context, without reproducing their problems. An Encapsulating Façade de-couples the client system entirely from the sub-system, which means the sub-systems can be swapped, eliminated, crippled, etc... This allows for easy creation of
- Demo versions of software. A demo version of the Façade can create stubbed-out behavior for the sub-system, and stand it its place, allowing the "front end" system to be demonstrated without the backend software/hardware present.
- Crippled versions of software. A crippling Façade can create a limited-functionality version of a system, which can easily be upgraded to the full version by replacing the crippling Façade with the full Façade.
- Testing. The Façade can be Mocked or Faked (see Testing Issues above) making the client system testable, which would otherwise be much more difficult.
- Training versions of software. Similar to Demos, a training Façade can be used to create predictable scenarios for training, while allowing the students to interact with the "real" front end of the overall system.
Facade and N-Tier Architectures
Imagine we are working on an application with a 3-tiered architecture (UI, Middle, Data), and we want to work in a test-driven way. Unfortunately, our teams are all blocked, because...
- UI Tier – "I can’t start until the middle tier is done, they provide the interface for the services I will consume."
- Middle Tier – "I can’t start until the data-layer is done, because I need to access it in order to provide services to the UI. I also need to know the persistence schemas, etc..."
- Data Layer – "I can’t start until I know what the data needs are. Also, I am involved in day-to-day business, which must always take priority over new development. I'll get to it when I get to it."
We can use Façades to separate these layers. The Façades (initially just stubs - interfaces with no implementation, or implemented to throw exceptions) will present an interface deemed ideal to the consuming layer. Also, each Façade "Stub" will be a mockable entity, and so the layers can be test-driven.
Later these stubs can be evolved into full-fledged Facades..
...given the implementation of the service layer in each case when this becomes available. This means that teams do not have to wait for dependencies to be ready, and in fact decouples them from specifics for good and all. Note that the same test will pass when the stubs evolves in each case, because the Facade itself can be mocked, and sports the same interface as the stub did.