Diagram of the Facade pattern
The Facade design pattern is basically a simplified interface to a complicated sub-system. Using facades is one more step in creating loose coupling between sub-systems while at the same time simplifying the functionality exposed from a sub-system.
Facades are sometimes known as facets.
A facade is used in situations where the full power of a sub-system isn't needed but the sub-system needs to be kept intact. In effect, a facade provides a "beginner's" interface to a complicated chunk of code whereas the API of the complicated chunk of code is for "advanced" users.
A simplification of a complex system could mean providing a high level function that uses a number of lower level functions in the complex system. Or the facade could provide only a few of the entry points into the complex system so the interface is kept simple.
Another way of thinking about Facades is on a large system that exposes many different interfaces, depending on what entity needs to access the system. Each entity sees only the interface exposed to it by the large system. A specific example of this is Visual Studio.
Visual Studio enables plugins through the Component Object Model (COM) architecture of Windows. A COM interface can be obtained from an implementation class (COM Class or coclass). A coclass can implement multiple different COM interfaces. From any interface, any other interface on that coclass can be requested. A Visual Studio plugin is a coclass that implements multiple interfaces exposed to Visual Studio. Those interfaces on the plugin are facades to the plugin. Visual Studio itself is exposed to the plugin through different COM interfaces, which become the facades on the Visual Studio system.
In other words, COM is a formalized mechanism to expose facades (interfaces) on a particular system to other entities that themselves could expose facades in return.
One thing to keep in mind is the Facade does not add any functionality, it only simplifies what is available. This means the Facade interface generally does not retain any state of its own, leaving that to the complicated sub-system. The Facade might retain one or more tokens or handles from the sub-system to facilitate access to the sub-system.
How to Use
The example provided is a complicated sub-system with many different low- level functions. This functionality is exposed through a low level interface. A facade is provided through a second interface that exposes a simplified set of functions for most common operations.
C++
void Facade_Exercise()
{
std::cout << std::endl;
std::cout << "Facade Exercise" << std::endl;
int numChains = deviceChainFacade->
NumChains();
std::cout
<< " Showing idcodes of devices after a device reset (expect one device on each chain)..."
<< std::endl;
for (int chainIndex = 0; chainIndex < numChains; ++chainIndex)
{
std::vector<uint32_t> idcodes = deviceChainFacade->
GetIdcodes(chainIndex);
}
std::cout << " Showing idcodes of devices after selecting all devices..."
<< std::endl;
for (int chainIndex = 0; chainIndex < numChains; ++chainIndex)
{
std::vector<uint32_t> idcodes = deviceChainFacade->
GetIdcodes(chainIndex);
}
std::cout << " Done." << std::endl;
}
static void _Facade_ShowIdCodes(int chainIndex, UIntArray *idcodes)
Helper function to present a formatted list of idcodes for a particular device chain....
Represents a high level view of a complex network of device chains. A device chain can be thought of ...
void(* EnableDevicesInDeviceChain)(int chainIndex, uint32_t selectMask)
Make visible certain devices in the given device chain. The selectMask value has a bit set for each d...
int(* NumChains)(void)
The number of device chains available from the sub-system.
void(* GetIdcodes)(int chainIndex, UIntArray *idcodes)
Returns a list of all idcodes from all selected devices in the given device chain.
void(* DisableDevicesInDeviceChain)(int chainIndex)
Resets the given device chain so that all devices except the first are no longer visible.
C#
public void Run()
{
Console.WriteLine();
Console.WriteLine("Facade Exercise");
Console.WriteLine(" Showing idcodes of devices after a device reset (expect one device on each chain)...");
for (int chainIndex = 0; chainIndex < numChains; ++chainIndex)
{
uint[] idcodes = deviceChainFacade.
GetIdcodes(chainIndex);
}
Console.WriteLine(" Showing idcodes of devices after selecting all devices...");
for (int chainIndex = 0; chainIndex < numChains; ++chainIndex)
{
uint[] idcodes = deviceChainFacade.
GetIdcodes(chainIndex);
}
Console.WriteLine(" Done.");
}
Python
def Facade_Exercise():
print()
print("Facade Exercise")
deviceChainFacade = CreateHighLevelInstance()
numChains = deviceChainFacade.GetNumChains()
print(" Showing idcodes of devices after a device reset (expect one device on each chain)...")
for chainIndex in range(0, numChains):
deviceChainFacade.DisableDevicesInDeviceChain(chainIndex)
idcodes = deviceChainFacade.GetIdcodes(chainIndex)
print(" Showing idcodes of devices after selecting all devices...")
for chainIndex in range(0, numChains):
deviceChainFacade.EnableDevicesInDeviceChain(chainIndex, 0xffffffff)
idcodes = deviceChainFacade.GetIdcodes(chainIndex)
print(" Done.")
C
void Facade_Exercise(void)
{
printf("\nFacade_Exercise\n");
if (deviceChainFacade != NULL)
{
int numChains = deviceChainFacade->
NumChains();
printf(" Showing idcodes of devices after a device reset (expect one device on each chain)...\n");
for (int chainIndex = 0; chainIndex < numChains; ++chainIndex)
{
deviceChainFacade->
GetIdcodes(chainIndex, &idcodes);
}
printf(" Showing idcodes of devices after selecting all devices...\n");
for (int chainIndex = 0; chainIndex < numChains; ++chainIndex)
{
deviceChainFacade->
GetIdcodes(chainIndex, &idcodes);
}
}
printf(" Done.\n");
}
IDeviceNetworkHighLevel * Facade_GetHighLevelDeviceService(void)
Retrieve a set of function pointers to the high-level device service used in the Facade Pattern examp...
Represents an array of 32-bit unsigned integers. The data field points to a block of memory allocated...
void UIntArray_Initialize(UIntArray *array)
Initialize the given UIntArray object.
void UIntArray_Clear(UIntArray *array)
Clear the given UIntArray object so it can be reused again. Releases the list of integers.
Rust
(Apologies. Doxygen does not understand Rust syntax and therefore cannot colorize the code.)
pub fn facade_exercise() -> Result<(), String> {
println!("");
println!("Facade Exercise");
let mut device_chain_facade = DeviceNetworkHighLevel::new();
let chain_count = device_chain_facade.num_chains();
println!(" Showing idcodes of devices after a device reset (expect one device on each chain)...");
for chain_index in 0..chain_count {
device_chain_facade.disable_devices_in_device_chain(chain_index);
let idcodes = device_chain_facade.get_idcodes(chain_index);
_facade_show_id_codes(chain_index, &idcodes);
}
println!(" Showing idcodes of devices after selecting all devices...");
for chain_index in 0..chain_count {
device_chain_facade.enable_devices_in_device_chain(chain_index, 0xffffffff);
let idcodes = device_chain_facade.get_idcodes(chain_index);
_facade_show_id_codes(chain_index, &idcodes);
}
println!(" Done.");
Ok(())
}
See Also