Skip to content

Commit 1b95d25

Browse files
committed
Add proxy pattern
1 parent 098c3ea commit 1b95d25

3 files changed

Lines changed: 260 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ set(APP_SOURCES
9191
"src/core/datatypes/class/CDestructors.cpp"
9292
"src/patterns/structural/Adapter.cpp"
9393
"src/patterns/structural/Bridge.cpp"
94+
"src/patterns/structural/Proxy.cpp"
9495
)
9596

9697
# Test files

docs/uml/patterns_structural_proxy.drawio.svg

Lines changed: 4 additions & 0 deletions
Loading

src/patterns/structural/Proxy.cpp

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
// Proxy is a structural design pattern that provides an object that acts as a substitute for a real service object used by a client.
2+
// A proxy receives client requests, does some work (access control, caching, etc.) and then passes the request to a service object.
3+
// UML: docs/uml/patterns_structural_proxy.drawio.svg
4+
5+
#include <iostream>
6+
7+
namespace Problem
8+
{
9+
const std::string admin = "admin";
10+
11+
class IServer
12+
{
13+
public:
14+
virtual ~IServer() = default;
15+
virtual void request1() = 0;
16+
virtual void request2() = 0;
17+
virtual void request3() = 0;
18+
};
19+
20+
class Server : public IServer
21+
{
22+
private:
23+
std::string _id;
24+
25+
public:
26+
explicit Server(const std::string &id) : _id{id}
27+
{
28+
// [P1] Heavy or complex construction, so ideally should be lazy-loaded
29+
std::cout << "[Server] Constructor: " << _id << "\n";
30+
}
31+
32+
// [P2] Need access control
33+
// [P3] Need to log requests without modifying the Server itself
34+
void request1() override
35+
{
36+
if (_id != admin)
37+
{
38+
std::cout << "[Server] Invalid ID: " << _id << "\n";
39+
return;
40+
}
41+
std::cout << "[Server] Handling request-1 for: " << _id << "\n";
42+
}
43+
44+
void request2() override
45+
{
46+
if (_id != admin)
47+
{
48+
std::cout << "[Server] Invalid ID: " << _id << "\n";
49+
return;
50+
}
51+
std::cout << "[Server] Handling request-2 for: " << _id << "\n";
52+
}
53+
54+
void request3() override
55+
{
56+
if (_id != admin)
57+
{
58+
std::cout << "[Server] Invalid ID: " << _id << "\n";
59+
return;
60+
}
61+
std::cout << "[Server] Handling request-3 for: " << _id << "\n";
62+
}
63+
};
64+
65+
namespace Client
66+
{
67+
void clientCode(IServer *s)
68+
{
69+
if (s != nullptr)
70+
{
71+
s->request1();
72+
s->request2();
73+
s->request3();
74+
}
75+
}
76+
}
77+
78+
void run()
79+
{
80+
std::cout << "\n\n";
81+
82+
{
83+
std::string connectionId = "admin";
84+
// [P4] The Server is constructed immediately even if we do not call any requests
85+
IServer *server = new Server(connectionId);
86+
std::cout << "User request\n";
87+
Client::clientCode(server);
88+
delete server;
89+
}
90+
91+
{
92+
// [P4] Server is constructed even for invalid ID, wasting resources
93+
std::string invalidId = "xxx";
94+
Server *server = new Server(invalidId);
95+
Client::clientCode(server);
96+
delete server;
97+
}
98+
}
99+
}
100+
101+
namespace ProxyPattern
102+
{
103+
const std::string admin = "admin";
104+
105+
class IServer
106+
{
107+
public:
108+
virtual ~IServer() = default;
109+
virtual void request1() = 0;
110+
virtual void request2() = 0;
111+
virtual void request3() = 0;
112+
};
113+
114+
class Server : public IServer
115+
{
116+
private:
117+
std::string _id;
118+
119+
public:
120+
explicit Server(const std::string &id) : _id{id}
121+
{
122+
std::cout << "[Server] Constructor: " << _id << "\n";
123+
}
124+
125+
void request1() override
126+
{
127+
std::cout << "[Server] Handling request-1 for: " << _id << "\n";
128+
}
129+
130+
void request2() override
131+
{
132+
std::cout << "[Server] Handling request-2 for: " << _id << "\n";
133+
}
134+
135+
void request3() override
136+
{
137+
std::cout << "[Server] Handling request-3 for: " << _id << "\n";
138+
}
139+
};
140+
141+
class ServerProxy : public IServer
142+
{
143+
private:
144+
std::string _id;
145+
Server *_server;
146+
147+
bool checkAccess()
148+
{
149+
std::cout << "[Proxy] Checking access before forwarding request.\n";
150+
if (_id != admin)
151+
{
152+
return false;
153+
}
154+
155+
// Lazy initialization: construct Server only on first access
156+
if (_server == nullptr)
157+
{
158+
_server = new Server(_id);
159+
}
160+
return true;
161+
}
162+
163+
void logAccess() const
164+
{
165+
std::cout << "[Proxy] Logging request time: " << _id << " .\n";
166+
}
167+
168+
public:
169+
explicit ServerProxy(const std::string &id) : _id{id}, _server{nullptr}
170+
{
171+
std::cout << "[Proxy] Constructor: " << _id << "\n";
172+
}
173+
174+
~ServerProxy()
175+
{
176+
std::cout << "[Proxy] Destructor: " << _id << "\n";
177+
if (_server != nullptr)
178+
{
179+
delete _server;
180+
}
181+
}
182+
183+
void request1() override
184+
{
185+
if (checkAccess())
186+
{
187+
_server->request1();
188+
logAccess();
189+
}
190+
}
191+
192+
void request2() override
193+
{
194+
if (checkAccess())
195+
{
196+
_server->request2();
197+
logAccess();
198+
}
199+
}
200+
201+
void request3() override
202+
{
203+
if (checkAccess())
204+
{
205+
_server->request3();
206+
logAccess();
207+
}
208+
}
209+
};
210+
211+
namespace Client
212+
{
213+
void clientCode(IServer *s)
214+
{
215+
if (s != nullptr)
216+
{
217+
s->request1();
218+
s->request2();
219+
s->request3();
220+
}
221+
}
222+
}
223+
224+
void run()
225+
{
226+
std::cout << "\n\n";
227+
228+
{
229+
std::string connectionId = "admin";
230+
// Server is not constructed until first request is made
231+
IServer *server = new ServerProxy(connectionId);
232+
std::cout << "User request\n";
233+
Client::clientCode(server);
234+
delete server;
235+
}
236+
237+
// Server is not constructed if id is invalid
238+
std::string invalidId = "xxx";
239+
Server *server = new Server(invalidId);
240+
Client::clientCode(server);
241+
delete server;
242+
}
243+
}
244+
245+
struct ProxyAutoRunner
246+
{
247+
ProxyAutoRunner()
248+
{
249+
std::cout << "\n--- Proxy Pattern Example ---\n";
250+
Problem::run();
251+
ProxyPattern::run();
252+
}
253+
};
254+
255+
static ProxyAutoRunner instance;

0 commit comments

Comments
 (0)