Patterns. The Facade Pattern

The Facade Pattern


Contents


Search other resources:

1. General information. Figure

Pattern Facade refers to patterns that structure objects. The pattern is intended to make it easier to use different subsystems by introducing a higher level interface. The introduced interface is unified and replaces the set of interfaces of some subsystem.

To facilitate the design of a complex system, this system is broken down into a number of smaller subsystems. At the same time, it is important that:

  • subsystems depended on each other at least;
  • the exchange of information between subsystems was minimal.

To solve this problem, a special object is used – the facade. This object represents a single simplified interface for more complex subsystems.

Figure 1 illustrates the essence of using a facade object to facilitate client access to subsystems.

The Facade Pattern

Figure 1. The Facade Pattern

The Facade pattern is based on the approach shown in Figure 1. A class (interface) is introduced into the system, containing simplified means (methods, fields, etc.) that provide access to more complex subsystems. There are several ways to implement this class.

 

2. An example of solving a problem using the Facade pattern
2.1. Task

The interaction between two subsystems (Figure 2) represented by the interfaces InterfaceA and InterfaceB is specified. Using the Facade pattern, implement a unified interface for the interaction of these subsystems.

The Facade pattern. Subsystems A, B and interaction of clients with these subsystems

Figure 2. Subsystems A, B and interaction of clients with these subsystems

 

2.2. Solution (Figure)

Figure 2 shows a solution using the Facade pattern to the problem shown in Figure 1.

The Facade pattern. Interaction between subsystems through a unified interface

Figure 3. Interaction between subsystems through a unified interface using the Facade pattern

 

2.3. The text of the solution of the problem in C ++

 

#include <iostream>
using namespace std;

// The Facade pattern
// ----------------------------------------
// Subsystem classes 1
// Interface
class InterfaceA abstract
{
public:
  virtual void MethodA() = 0;
};

class ClassA1 : public InterfaceA
{
public:
  void MethodA() override
  {
    cout << "ClassA1::MethodA()" << endl;
  }
};

class ClassA2 : public InterfaceA
{
public:
  void MethodA() override
  {
    cout << "ClassA2::MethodA()" << endl;
  }
};

// ----------------------------------------
// Subsystem classes 2
// Interface
class InterfaceB abstract
{
public:
  virtual void MethodB() = 0;
};

class ClassB1 : public InterfaceB
{
public:
  void MethodB() override
  {
    cout << "ClassB1::MethodB()" << endl;
  }
};

class ClassB2 : public InterfaceB
{
public:
  void MethodB() override
  {
    cout << "ClassB2::MethodB()" << endl;
  }
};

// A class that is a facade.
// The class implements a simplified interface
// for the most common case, this is the main idea.
class Facade
{
public:
  void FacadeMethodA(InterfaceA* obj)
  {
    obj->MethodA();
  }

  void FacadeMethodB(InterfaceB* obj)
  {
    obj->MethodB();
  }
};

void main()
{
  // Client code
  // Real implementations
  ClassA1* objA1 = new ClassA1;
  ClassA2* objA2 = new ClassA2;
  ClassB1* objB1 = new ClassB1;
  ClassB2* objB2 = new ClassB2;

  // Clients A, B
  Facade* ClientA = new Facade;
  Facade* ClientB = new Facade;

  // Method calls
  // Client A's access to the MethodA() method of ClassA1
  ClientA->FacadeMethodA(objA1);

  // Client B's access to MethodB() of ClassB2
  ClientB->FacadeMethodB(objB2);

  // Client B's access to the MethodA() method of class ClassA2
  ClientB->FacadeMethodA(objA2);

  // Free up memory after the pattern has been demonstrated
  if (objA1) delete objA1;
  if (objA2) delete objA2;
  if (objB1 != nullptr) delete objB1;
  if (objB2) delete objB2;
  if (ClientA) delete ClientA;
  if (ClientB) delete ClientB;
}

 

3. Cases for using the Facade pattern

The Facade pattern is used in the following cases.

  1. When it is necessary to provide a simple interface to a complex subsystem. In the process of development, subsystems change and can become more complex. Changes require additional settings for certain requirements. The Facade pattern offers some default system configuration that will satisfy most clients. At the same time, if you need to implement more complex settings, then the corresponding objects can access the subsystem objects directly bypassing the Facade pattern.
  2. When there are many dependencies between clients and abstraction implementation classes. The Facade pattern separates a subsystem from clients and other systems. In this way, better portability and independence is ensured.
  3. The need to split the subsystem into separate layers. In this case, entry points to each level of the subsystem are determined, and a facade is formed at each entry point. Here it is important to establish the rule of exchange between subsystems only through facades.

 

4. The structure of the Facade pattern (figure). Pattern participants

Figure 4 shows the structure of the Facade pattern. This structure is generalized.

Structure of the Facade Pattern

Figure 4. Structure of the Facade Pattern

In the above structure (Figure 4), the Facade class (participant) performs the following functions:

  • defines the subsystem classes to which the request is implemented;
  • makes redirection (delegation) of client requests to those objects of the subsystem that are suitable for them.

Subsystem classes perform the following functions:

  • implement the functionality of the subsystem;
  • perform the work established by the Facade object;
  • do not store references to the Facade object (do not “know” the existence of the facade).

 

5. Relations

Interaction of clients with a subsystem is carried out through a facade. The facade receives requests from clients and forwards them to objects within the system. In this case, a situation is possible when the facade will need to attach its interface to the needs of the classes (objects) of the subsystem. If clients use a facade, they do not have direct access to subsystem classes.

 

6. Results

Using the Facade pattern provides the following benefits.

  1. Separation (isolation) of clients from subsystem components reduces the number of objects used by clients. This, in turn, simplifies the work with the subsystem.
  2. The connection between the subsystem and its clients is reduced. This makes it possible to modify components without affecting clients. Using facades allows you to break the system into layers and structure the dependencies between objects. If there are complex cyclic dependencies between the objects of the subsystem, then with the help of facades these dependencies can be avoided.

As a consequence, changing one subsystem will have little or no effect on the other subsystem. This simplifies portability of the system to other platforms.

  1. If necessary, the client code can directly access the classes of the subsystem. In this case, the facade does not install any obstacles. Thus, there is a choice between general and simplified.

 

7. Features of implementation

When implementing the Facade pattern, you should pay attention to the following issues.

  1. The degree of connection between the client and the subsystem is reduced. The Facade class can be abstract with different implementations in the form of inherited classes. In this case, the degree of connectivity with the subsystem is significantly reduced.

There is another approach. Using the Facade object with various objects customized for specific subsystems.

  1. Features of the use of open and closed classes of subsystems. Any subsystem can have public classes (interfaces) and classes that are closed to other code. The facade provides access to public (public) interfaces, although other subsystem classes may be public.

 


Related topics