The Facade Pattern
Contents
- 1. General information. Figure
- 2. An example of solving a problem using the Facade pattern
- 3. Cases for using the Facade pattern
- 4. The structure of the Facade pattern (figure). Pattern participants
- 5. Relations
- 6. Results
- 7. Features of implementation
- Related topics
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.
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.
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.
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.
- 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.
- 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.
- 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.
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.
- Separation (isolation) of clients from subsystem components reduces the number of objects used by clients. This, in turn, simplifies the work with the subsystem.
- 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.
- 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.
- 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.
- 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
- Pattern Adapter. Review and research. Examples of implementation in C++
- Bridge pattern. Implementation of structure in C++
- Composite pattern. Implementation of structure in C++
⇑