1+ // cppcheck-suppress-file [functionStatic]
2+
3+ // Facade is a structural design pattern that provides a simplified interface
4+ // to a library, a framework, or any other complex set of classes.
5+ // Appicability:
6+ // (*) when you need to have a limited but straightforward interface to a complex subsystem.
7+ // (**) when you want to structure a subsystem into layers.
8+ // UML: none
9+
10+ #include < iostream>
11+ namespace
12+ {
13+ namespace Problem
14+ {
15+
16+ class AuthSubSystem
17+ {
18+ public:
19+ virtual ~AuthSubSystem () = default ;
20+ void login () const
21+ {
22+ std::cout << " AuthSubSystem: login\n " ;
23+ }
24+ };
25+
26+ class ValidatorSubSystem
27+ {
28+ public:
29+ virtual ~ValidatorSubSystem () = default ;
30+ virtual void check () const
31+ {
32+ std::cout << " ValidatorSubSystem: check input\n " ;
33+ }
34+ };
35+
36+ class LoggerSubSystem
37+ {
38+ public:
39+ virtual ~LoggerSubSystem () = default ;
40+ void write () const
41+ {
42+ std::cout << " LoggerSubSystem: write log\n " ;
43+ }
44+ };
45+
46+ class BackendSubSystem
47+ {
48+ public:
49+ virtual ~BackendSubSystem () = default ;
50+ void send () const
51+ {
52+ std::cout << " BackendSubSystem: send request\n " ;
53+ }
54+ };
55+
56+ namespace Client1
57+ {
58+ // The client must manually interact with each subsystem.
59+ // This creates unnecessary complexity.
60+ void clientCode (const ValidatorSubSystem &s1, const AuthSubSystem &s2, const LoggerSubSystem &s3, const BackendSubSystem &s4)
61+ {
62+ s1.check ();
63+ s2.login ();
64+ s3.write ();
65+ s4.send ();
66+
67+ // In real code, the client must also
68+ // - know call ordering
69+ // - combine subsystem operations
70+ // - manage lifecycle and error handling
71+ }
72+ }
73+
74+ namespace Client2
75+ {
76+ // The client must manually interact with each subsystem.
77+ // This creates unnecessary complexity.
78+ void clientCode (const ValidatorSubSystem &s1)
79+ {
80+ s1.check ();
81+ }
82+ }
83+
84+ void run ()
85+ {
86+ std::cout << " \n\n Problem\n " ;
87+
88+ ValidatorSubSystem v;
89+ AuthSubSystem a;
90+ LoggerSubSystem l;
91+ BackendSubSystem b;
92+
93+ Client1::clientCode (v, a, l, b);
94+ Client2::clientCode (v);
95+ }
96+ }
97+
98+ namespace Facade
99+ {
100+
101+ class AuthSubSystem
102+ {
103+ public:
104+ virtual ~AuthSubSystem () = default ;
105+ void login () const
106+ {
107+ std::cout << " AuthSubSystem: login\n " ;
108+ }
109+ };
110+
111+ class ValidatorSubSystem
112+ {
113+ public:
114+ virtual ~ValidatorSubSystem () = default ;
115+ void check () const
116+ {
117+ std::cout << " ValidatorSubSystem: check input\n " ;
118+ }
119+ };
120+
121+ class LoggerSubSystem
122+ {
123+ public:
124+ virtual ~LoggerSubSystem () = default ;
125+ void write () const
126+ {
127+ std::cout << " LoggerSubSystem: write log\n " ;
128+ }
129+ };
130+
131+ class BackendSubSystem
132+ {
133+ public:
134+ virtual ~BackendSubSystem () = default ;
135+ virtual void send () const
136+ {
137+ std::cout << " BackendSubSystem: send request\n " ;
138+ }
139+ };
140+
141+ // =======================
142+ // Mock subclasses (for testing)
143+ // =======================
144+ class MockBackendSubSystem : public BackendSubSystem
145+ {
146+ public:
147+ void send () const override
148+ {
149+ std::cout << " [MockBackend] fake-send\n " ;
150+ }
151+ };
152+
153+ /* *
154+ * The Facade class provides a simple interface to the complex logic of one or
155+ * several subsystems. The Facade delegates the client requests to the
156+ * appropriate objects within the subsystem. The Facade is also responsible for
157+ * managing their lifecycle. All of this shields the client from the undesired
158+ * complexity of the subsystem.
159+ */
160+ class RequestFacade
161+ {
162+ protected:
163+ const AuthSubSystem *auth_;
164+ const ValidatorSubSystem *validator_;
165+ const LoggerSubSystem *logger_;
166+ const BackendSubSystem *backend_;
167+
168+ /* *
169+ * Depending on your application's needs, you can provide the Facade with
170+ * existing subsystem objects or force the Facade to create them on its own.
171+ */
172+ public:
173+ /* *
174+ * In this case we will delegate the memory ownership to Facade Class
175+ */
176+ explicit RequestFacade (const AuthSubSystem *s1 = nullptr ,
177+ const ValidatorSubSystem *s2 = nullptr ,
178+ const LoggerSubSystem *s3 = nullptr ,
179+ const BackendSubSystem *s4 = nullptr )
180+ {
181+ this ->auth_ = s1 ?: new AuthSubSystem;
182+ this ->validator_ = s2 ?: new ValidatorSubSystem;
183+ this ->logger_ = s3 ?: new LoggerSubSystem;
184+ this ->backend_ = s4 ?: new BackendSubSystem;
185+ }
186+
187+ ~RequestFacade ()
188+ {
189+ delete auth_;
190+ delete validator_;
191+ delete logger_;
192+ delete backend_;
193+ }
194+
195+ /* *
196+ * The Facade's methods are convenient shortcuts to the sophisticated
197+ * functionality of the subsystems. However, clients get only to a fraction of
198+ * a subsystem's capabilities.
199+ */
200+ void sendRequest () const
201+ {
202+ validator_->check ();
203+ auth_->login ();
204+ logger_->write ();
205+ backend_->send ();
206+ }
207+
208+ void validate () const
209+ {
210+ validator_->check ();
211+ }
212+ };
213+
214+ namespace Client1
215+ {
216+ /* *
217+ * The client code works with complex subsystems through a simple interface
218+ * provided by the Facade. When a facade manages the lifecycle of the subsystem,
219+ * the client might not even know about the existence of the subsystem. This
220+ * approach lets you keep the complexity under control.
221+ */
222+ void clientCode (const RequestFacade &facade)
223+ {
224+ facade.sendRequest ();
225+ }
226+ }
227+
228+ namespace Client2
229+ {
230+ /* *
231+ * The client code works with complex subsystems through a simple interface
232+ * provided by the Facade. When a facade manages the lifecycle of the subsystem,
233+ * the client might not even know about the existence of the subsystem. This
234+ * approach lets you keep the complexity under control.
235+ */
236+ void clientCode (const RequestFacade &facade)
237+ {
238+ facade.validate ();
239+ }
240+ }
241+
242+ void run ()
243+ {
244+ std::cout << " \n\n Facade\n " ;
245+ {
246+ RequestFacade *facade = new RequestFacade ();
247+ Client1::clientCode (*facade);
248+ Client2::clientCode (*facade);
249+ delete facade;
250+ }
251+
252+ {
253+ // injected subsystems for mocktest
254+ std::cout << " \n " ;
255+ const MockBackendSubSystem *b = new MockBackendSubSystem ();
256+ RequestFacade *facade = new RequestFacade (nullptr , nullptr , nullptr , b);
257+ Client1::clientCode (*facade);
258+ delete facade;
259+ }
260+ }
261+ }
262+ }
263+
264+ struct FacadeAutoRuner
265+ {
266+ FacadeAutoRuner ()
267+ {
268+ std::cout << " \n --- Facade Pattern Example ---\n " ;
269+ Problem::run ();
270+ Facade::run ();
271+ }
272+ };
273+
274+ static FacadeAutoRuner instance;
0 commit comments