Skip to content

Commit 1e45aee

Browse files
authored
Merge pull request #13 from urboob21/dev_branch
id 1763281728
2 parents 8abda8b + 57b6f1d commit 1e45aee

File tree

4 files changed

+280
-1
lines changed

4 files changed

+280
-1
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ set(APP_SOURCES
9696
"src/patterns/structural/Proxy.cpp"
9797
"src/patterns/structural/Composite.cpp"
9898
"src/patterns/structural/Flyweight.cpp"
99+
"src/patterns/structural/Facade.cpp"
99100
)
100101

101102
# Test files

docs/uml/patterns_structural_facade.drawio.svg

Lines changed: 4 additions & 0 deletions
Loading

src/patterns/structural/Composite.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// Appicability:
55
// (*) when you have to implement a tree-like object structure.
66
// (**) when you want the client code to treat both simple and complex elements uniformly.
7-
// UML: docs/uml/patterns_structural_Composite.drawio.svg
7+
// UML: docs/uml/patterns_structural_facade.drawio.svg
88

99
#include <iostream>
1010
#include <string>

src/patterns/structural/Facade.cpp

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
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\nProblem\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\nFacade\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

Comments
 (0)