26.9. Facade (GoF)
Another requirement chosen for this iteration is pluggable business rules . That is, at predictable points in the scenarios, such as when makeNewSale or enterItem occurs in the Process Sale use case, or when a cashier starts cashing in, different customers who wish to purchase the NextGen POS would like to customize its behavior slightly.To be more precise, assume that rules are desired that can invalidate an action. For example:
- Suppose when a new sale is created, it is possible to identify that it will be paid by a gift certificate (this is possible and common). Then, a store may have a rule to only allow one item to be purchased if a gift certificate is used. Consequently, subsequent enterItem operations, after the first, should be invalidated.
- If the sale is paid by a gift certificate, invalidate all payment types of change due back to the customer except for another gift certificate. For example, if the cashier requested change in the form of cash, or as a credit to the customer's store account, invalidate those requests.
- Suppose when a new sale is created, it is possible to identify that it is for a charitable donation (from the store to the charity). A store may also have a rule to only allow item entries less than $250 each, and also to only add items to the sale if the currently logged in "cashier" is a manager.
In terms of requirements analysis, the specific scenario points across all use cases (enterItem, chooseCashChange , ...) must be identified. For this exploration, only the enterItem point will be considered, but the same solution applies equally to all points.Suppose that the software architect wants a design that has low impact on the existing software components. That is, she or he wants to design for a separation of concerns, and factor out this rule handling into a separate concern. Furthermore, suppose that the architect is unsure of the best implementation for this pluggable rule handling, and may want to experiment with different solutions for representing, loading, and evaluating the rules. For example, rules can be implemented with the Strategy pattern, or with free open-source rule interpreters that read and interpret a set of IF-THEN rules, or with commercial, purchased rule interpreters, among other solutions.To solve this design problem, the Facade pattern can be used.
Name: | Facade |
Problem: | A common, unified interface to a disparate set of implementations or interfacessuch as within a subsystemis required. There may be undesirable coupling to many things in the subsystem, or the implementation of the subsystem may change. What to do? |
Solution: (advice) | Define a single point of contact to the subsystema facade object that wraps the subsystem. This facade object presents a single unified interface and is responsible for collaborating with the subsystem components. |
[2] "Subsystem" is here used in an informal sense to indicate a separate grouping of related components, not exactly as defined in the UML.
For example, we will define a "rule engine" subsystem, whose specific implementation is not yet known.[3] It will be responsible for evaluating a set of rules against an operation (by some hidden implementation), and then indicating if any of the rules invalidated the operation.
[3] There are several free open source and commercial rule engines. For example, Jess, a free-for-academic-use rule engine available at http://herzberg.ca.sandia.gov/jess/.
The facade object to this subsystem will be called POSRuleEngineFacade . See Figure 26.20. The designer decides to place calls to this facade near the start of the methods that have been defined as the points for pluggable rules, as in this example:
public class Sale
{
public void makeLineItem( ProductDescription desc, int quantity )
{
SalesLineItem sli = new SalesLineItem( desc, quantity );
// call to the Facade
if ( POSRuleEngineFacade.getInstance().isInvalid( sli, this ) )
return;
lineItems.add( sli );
}
// ...
} // end of class
Figure 26.20. UML package diagram with a Facade.
[View full size image]
Summary
The Facade pattern is simple and widely used. It hides a subsystem behind an object.Related Patterns Facades are usually accessed via the Singleton pattern. They provide Protected Variations from the implementation of a subsystem, by adding an Indirection object to help support Low Coupling. External objects are coupled to one point in a subsystem: the facade object.As described in the Adapter pattern, an adapter object may be used to wrap access to external systems with varying interfaces. This is a kind of facade, but the emphasis is to provide adaptation to varying interfaces, and thus it is more specifically called an adapter.