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