© Jennifer M. Kohnke
Symbolism erects a facade of respectability to hide the indecency of dreams.
—Mason Cooley
The two patterns discussed in this chapter have a common purpose: imposing some kind of policy on another group of objects. FACADE imposes policy from above; MEDIATOR, from below. The use of FACADE is visible and constraining; that of MEDIATOR, invisible and enabling.
The FACADE pattern is used when you want to provide a simple and specific interface onto a group of objects that have a complex and general interface. Consider, for example, DB.cs
in Listing 34-9. This class imposes a very simple interface, specific to ProductData
, on the complex and general interfaces of the classes within the System.Data
namespace. Figure 23-1 shows the structure.
Notice that the DB
class protects the Application
from needing to know the intimacies of the System.Data
namespace. The class hides all the generality and complexity of System.Data
behind a very simple and specific interface.
A FACADE like DB
imposes a lot of policy on the usage of System.Data
, knowing how to initialize and close the database connection, translate the members of ProductData
into database fields and back, and build the appropriate queries and commands to manipulate the database. All that complexity is hidden from users. From the point of view of the Application
, System.Data
does not exist; it is hidden behind the FACADE.
The use of the FACADE pattern implies that the developers have adopted the convention that all database calls must go through DB
. If any part of the Application
code goes straight to System.Data
rather than through the FACADE, that convention is violated. As such, the FACADE imposes its polices on the application. By convention, DB
has become the sole broker of the facilities of System.Data
.
FACADE can be used to hide any aspect of a program. However, using FACADE to hide the database has become so common, the pattern is also known as TABLE DATA GATEWAY.
The MEDIATOR pattern also imposes policy. However, whereas FACADE imposes its policy in a visible and constraining way, MEDIATOR imposes its policies in a hidden and unconstraining way. For example, the QuickEntryMediator
class in Listing 23-1 sits quietly behind the scenes and binds a text-entry field to a list. When you type in the text-entry field, the first list element that matches what you have typed is highlighted. This lets you type abbreviations and quickly select a list item.
Listing 23-1. QuickEntryMediator.cs
using System;
using System.Windows.Forms;
/// <summary>
/// QuickEntryMediator. This class takes a TextBox and a
/// ListBox. It assumes that the user will type
/// characters into the TextBox that are prefixes of
/// entries in the ListBox. It automatically selects the
/// first item in the ListBox that matches the current
/// prefix in the TextBox.
///
/// If the TextField is null, or the prefix does not
/// match any element in the ListBox, then the ListBox
/// selection is cleared.
///
/// There are no methods to call for this object. You
/// simply create it, and forget it. (But don't let it
/// be garbage collected...)
///
/// Example:
///
/// TextBox t = new TextBox();
/// ListBox l = new ListBox();
///
/// QuickEntryMediator qem = new QuickEntryMediator(t,l);
/// // that's all folks.
///
/// Originally written in Java
/// by Robert C. Martin, Robert S. Koss
/// on 30 Jun, 1999 2113 (SLAC)
/// Translated to C# by Micah Martin
/// on May 23, 2005 (On the Train)
/// </summary>
public class QuickEntryMediator
{
private TextBox itsTextBox;
private ListBox itsList;
public QuickEntryMediator(TextBox t, ListBox l)
{
itsTextBox = t;
itsList = l;
itsTextBox.TextChanged += new EventHandler(TextFieldChanged);
}
private void
TextFieldChanged(object source, EventArgs args)
{
string prefix = itsTextBox.Text;
if (prefix.Length == 0)
{
itsList.ClearSelected();
return;
}
ListBox.ObjectCollection listItems = itsList.Items;
bool found = false;
for (int i = 0; found == false &&
i < listItems.Count; i++)
{
Object o = listItems[i];
String s = o.ToString();
if (s.StartsWith(prefix))
{
itsList.SetSelected(i, true);
found = true;
}
}
if (!found)
{
itsList.ClearSelected();
}
}
}
The structure of the QuickEntryMediator
is shown in Figure 23-2. An instance of QuickEntryMediator
is constructed with a ListBox
and a TextBox
. The Quick-EntryMediator
registers an EventHandler
with the TextBox
. This EventHandler
invokes the TextFieldChanged
method whenever there is a change in the text. This method then finds a ListBox
element that is prefixed by the text and selects it.
The users of the ListBox
and TextField
have no idea that this MEDIATOR exists. It quietly sits there, imposing its policy on those objects without their permission or knowledge.
Imposing policy can be done from above, using FACADE, if that policy needs to be big and visible. On the other hand, if subtlety and discretion are needed, MEDIATOR may be the more appropriate choice. FACADEs are usually the focal point of a convention. Everyone agrees to use the FACADE instead of the objects beneath it. MEDIATOR, on the other hand, is hidden from the users. Its policy is a fait accompli rather than a matter of convention.
[Fowler03] Martin Fowler, Patterns of Enterprise Application Architecture, Addison-Wesley, 2003.
[GOF95] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1995.
18.216.94.152