From 098c3ea823fbfca9f83eb6e62222cbddd1216bc2 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Wed, 12 Nov 2025 09:54:21 +0700 Subject: [PATCH 1/3] update doc --- docs/uml/patterns_structural_bridge.drawio.svg | 2 +- src/patterns/structural/Adapter.cpp | 4 +++- src/patterns/structural/Bridge.cpp | 5 +++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/uml/patterns_structural_bridge.drawio.svg b/docs/uml/patterns_structural_bridge.drawio.svg index 00b262f..5931500 100644 --- a/docs/uml/patterns_structural_bridge.drawio.svg +++ b/docs/uml/patterns_structural_bridge.drawio.svg @@ -1,4 +1,4 @@ -
Widget
 
+ clickOn(type): type
Client
+ clientCode(const Widget* widget): type
Use
Use
WidgetAbstraction

# _implementation : OsImplementation 
+ WidgetAbstraction(Implementation* impl)
+ clickOn(type): type
<<Interface>>
OsImplementation
+ clickOnImplement(type): type
1
Aggregation
WindowsImplementation
+ clickOnImplement(type): type
WindowsImplementation
+ clickOnImplement(type): type
...
+ clickOnImplement(type): type
1...n
Button
 
 
Label
 
 
Extends
Extends
ButtonWindows
 
+ clickOn(type): type
ButtonLinux
 
+ clickOn(type): type
LabelWindows
 
+ clickOn(type): type
LabelLinux
 
+ clickOn(type): type
Extends
Extends
Extends
Extends
Client
+ clientCode(const Widget* widget): type
ButtonAbstraction

ButtonAbstraction(Implementation* impl)
+ clickOn(type): type
LabelAbtraction
LabelAbtraction(Implementation* impl)
+ clickOn(type): type
...
+ clickOn(type): type
Extends
Extends
Extends
1...n
clickOn(){
this->_implementation->clickOnImplement()
...
}
bridge
\ No newline at end of file +
Widget
 
+ clickOn(type): type
Client
+ clientCode(const Widget* widget): type
Use
Use
WidgetAbstraction

# _implementation : OsImplementation* 
+ WidgetAbstraction(Implementation* impl)
+ clickOn(type): type
<<Interface>>
OsImplementation
+ clickOnImplement(type): type
1
Aggregation
WindowsImplementation
+ clickOnImplement(type): type
WindowsImplementation
+ clickOnImplement(type): type
...
+ clickOnImplement(type): type
1...n
Button
 
 
Label
 
 
Extends
Extends
ButtonWindows
 
+ clickOn(type): type
ButtonLinux
 
+ clickOn(type): type
LabelWindows
 
+ clickOn(type): type
LabelLinux
 
+ clickOn(type): type
Extends
Extends
Extends
Extends
Client
+ clientCode(const Widget* widget): type
ButtonAbstraction

ButtonAbstraction(Implementation* impl)
+ clickOn(type): type
LabelAbtraction
LabelAbtraction(Implementation* impl)
+ clickOn(type): type
...
+ clickOn(type): type
Extends
Extends
Extends
1...n
clickOn(){
this->_implementation->clickOnImplement()
...
}
bridge
\ No newline at end of file diff --git a/src/patterns/structural/Adapter.cpp b/src/patterns/structural/Adapter.cpp index 9d72a94..9174b22 100644 --- a/src/patterns/structural/Adapter.cpp +++ b/src/patterns/structural/Adapter.cpp @@ -1,6 +1,8 @@ +// Adapters make legacy code work with modern classes. +// UML: docs/uml/patterns_structural_adapter.drawio.svg + #include -// Adapters make legacy code work with modern classes. namespace AdapterPattern { /** diff --git a/src/patterns/structural/Bridge.cpp b/src/patterns/structural/Bridge.cpp index 796d08d..66a4657 100644 --- a/src/patterns/structural/Bridge.cpp +++ b/src/patterns/structural/Bridge.cpp @@ -1,3 +1,8 @@ +// Bridge lets we split a large class or a set of closely related classes +// into two separate hierarchies—abstraction and implementation +// which can be developed independently of each other. +// UML: docs/uml/patterns_structural_bridge.drawio.svg + #include namespace Problem From 1b95d25ef1cfe3a5f923e68b010abeb0326695f3 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Wed, 12 Nov 2025 15:10:05 +0700 Subject: [PATCH 2/3] Add proxy pattern --- CMakeLists.txt | 1 + docs/uml/patterns_structural_proxy.drawio.svg | 4 + src/patterns/structural/Proxy.cpp | 255 ++++++++++++++++++ 3 files changed, 260 insertions(+) create mode 100644 docs/uml/patterns_structural_proxy.drawio.svg create mode 100644 src/patterns/structural/Proxy.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 495f334..4b60f5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,7 @@ set(APP_SOURCES "src/core/datatypes/class/CDestructors.cpp" "src/patterns/structural/Adapter.cpp" "src/patterns/structural/Bridge.cpp" + "src/patterns/structural/Proxy.cpp" ) # Test files diff --git a/docs/uml/patterns_structural_proxy.drawio.svg b/docs/uml/patterns_structural_proxy.drawio.svg new file mode 100644 index 0000000..79dd3cf --- /dev/null +++ b/docs/uml/patterns_structural_proxy.drawio.svg @@ -0,0 +1,4 @@ + + + +proxy
Client
+ clientCode(IServer* s): type

<<Interface>>
IServer


+ requestName(): void
+ requestData(): void

+ requestFile(): void

Use

Server


- _id: string


+ Server(string id)

+ request1(): void
+ request2(): void

+ request3(): void

Implementation
int main(int argc, char* argv[ ]){
string id = "admin";
IServer server = new Server(id);
// P1
clientCode(server);
delete server;
}
// P2,P3...
void request*(){
 if(_id != "admin"){
return;
 }
 // do request
}
Client
+ clientCode(IServer* s): type

<<Interface>>
IServer


+ requestName(): void
+ requestData(): void

+ requestFile(): void

Use

Server


- _id: string


+ Server(string id)

+ request1(): void
+ request2(): void

+ request3(): void

Implementation

ServerProxy


- _id: string

- _server:  Server*


- checkAccess(): bool

- logAccess(): bool

+ ServerProxy(string id)

~ ServerProxy();

+ request1(): void
+ request2(): void

+ request3(): void

1
Composition
Implementation
bool checkAccess(){
 if(_id != "admin"){
return false;

 if(_server == nullptr){
 _server = new Server(_id);
}
}

void request*(){
 if(checkAccess()){
_server->request*();
 logAccess();
}
}

~ServerProxy(){
if(_server != nullptr){
delete _server;
}
int main(int argc, char* argv[ ]){
string id = "admin";
IServer server = new ServerProxy(id);
clientCode(server);
delete server;
}
\ No newline at end of file diff --git a/src/patterns/structural/Proxy.cpp b/src/patterns/structural/Proxy.cpp new file mode 100644 index 0000000..8e71f1d --- /dev/null +++ b/src/patterns/structural/Proxy.cpp @@ -0,0 +1,255 @@ +// Proxy is a structural design pattern that provides an object that acts as a substitute for a real service object used by a client. +// A proxy receives client requests, does some work (access control, caching, etc.) and then passes the request to a service object. +// UML: docs/uml/patterns_structural_proxy.drawio.svg + +#include + +namespace Problem +{ + const std::string admin = "admin"; + + class IServer + { + public: + virtual ~IServer() = default; + virtual void request1() = 0; + virtual void request2() = 0; + virtual void request3() = 0; + }; + + class Server : public IServer + { + private: + std::string _id; + + public: + explicit Server(const std::string &id) : _id{id} + { + // [P1] Heavy or complex construction, so ideally should be lazy-loaded + std::cout << "[Server] Constructor: " << _id << "\n"; + } + + // [P2] Need access control + // [P3] Need to log requests without modifying the Server itself + void request1() override + { + if (_id != admin) + { + std::cout << "[Server] Invalid ID: " << _id << "\n"; + return; + } + std::cout << "[Server] Handling request-1 for: " << _id << "\n"; + } + + void request2() override + { + if (_id != admin) + { + std::cout << "[Server] Invalid ID: " << _id << "\n"; + return; + } + std::cout << "[Server] Handling request-2 for: " << _id << "\n"; + } + + void request3() override + { + if (_id != admin) + { + std::cout << "[Server] Invalid ID: " << _id << "\n"; + return; + } + std::cout << "[Server] Handling request-3 for: " << _id << "\n"; + } + }; + + namespace Client + { + void clientCode(IServer *s) + { + if (s != nullptr) + { + s->request1(); + s->request2(); + s->request3(); + } + } + } + + void run() + { + std::cout << "\n\n"; + + { + std::string connectionId = "admin"; + // [P4] The Server is constructed immediately even if we do not call any requests + IServer *server = new Server(connectionId); + std::cout << "User request\n"; + Client::clientCode(server); + delete server; + } + + { + // [P4] Server is constructed even for invalid ID, wasting resources + std::string invalidId = "xxx"; + Server *server = new Server(invalidId); + Client::clientCode(server); + delete server; + } + } +} + +namespace ProxyPattern +{ + const std::string admin = "admin"; + + class IServer + { + public: + virtual ~IServer() = default; + virtual void request1() = 0; + virtual void request2() = 0; + virtual void request3() = 0; + }; + + class Server : public IServer + { + private: + std::string _id; + + public: + explicit Server(const std::string &id) : _id{id} + { + std::cout << "[Server] Constructor: " << _id << "\n"; + } + + void request1() override + { + std::cout << "[Server] Handling request-1 for: " << _id << "\n"; + } + + void request2() override + { + std::cout << "[Server] Handling request-2 for: " << _id << "\n"; + } + + void request3() override + { + std::cout << "[Server] Handling request-3 for: " << _id << "\n"; + } + }; + + class ServerProxy : public IServer + { + private: + std::string _id; + Server *_server; + + bool checkAccess() + { + std::cout << "[Proxy] Checking access before forwarding request.\n"; + if (_id != admin) + { + return false; + } + + // Lazy initialization: construct Server only on first access + if (_server == nullptr) + { + _server = new Server(_id); + } + return true; + } + + void logAccess() const + { + std::cout << "[Proxy] Logging request time: " << _id << " .\n"; + } + + public: + explicit ServerProxy(const std::string &id) : _id{id}, _server{nullptr} + { + std::cout << "[Proxy] Constructor: " << _id << "\n"; + } + + ~ServerProxy() + { + std::cout << "[Proxy] Destructor: " << _id << "\n"; + if (_server != nullptr) + { + delete _server; + } + } + + void request1() override + { + if (checkAccess()) + { + _server->request1(); + logAccess(); + } + } + + void request2() override + { + if (checkAccess()) + { + _server->request2(); + logAccess(); + } + } + + void request3() override + { + if (checkAccess()) + { + _server->request3(); + logAccess(); + } + } + }; + + namespace Client + { + void clientCode(IServer *s) + { + if (s != nullptr) + { + s->request1(); + s->request2(); + s->request3(); + } + } + } + + void run() + { + std::cout << "\n\n"; + + { + std::string connectionId = "admin"; + // Server is not constructed until first request is made + IServer *server = new ServerProxy(connectionId); + std::cout << "User request\n"; + Client::clientCode(server); + delete server; + } + + // Server is not constructed if id is invalid + std::string invalidId = "xxx"; + Server *server = new Server(invalidId); + Client::clientCode(server); + delete server; + } +} + +struct ProxyAutoRunner +{ + ProxyAutoRunner() + { + std::cout << "\n--- Proxy Pattern Example ---\n"; + Problem::run(); + ProxyPattern::run(); + } +}; + +static ProxyAutoRunner instance; \ No newline at end of file From 297e02847bb0d846873502a7b5c8bdeba3e8d0a3 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Wed, 12 Nov 2025 15:20:01 +0700 Subject: [PATCH 3/3] Fix multiple definition of `Problem::run()' --- src/patterns/structural/Bridge.cpp | 344 ++++++++++++++------------- src/patterns/structural/Proxy.cpp | 370 +++++++++++++++-------------- 2 files changed, 359 insertions(+), 355 deletions(-) diff --git a/src/patterns/structural/Bridge.cpp b/src/patterns/structural/Bridge.cpp index 66a4657..ea974bd 100644 --- a/src/patterns/structural/Bridge.cpp +++ b/src/patterns/structural/Bridge.cpp @@ -4,209 +4,211 @@ // UML: docs/uml/patterns_structural_bridge.drawio.svg #include - -namespace Problem +namespace { - class Widget + namespace Problem { - public: - virtual ~Widget() = default; - virtual std::string clickOn() const = 0; - }; - - /* Concrete variations for Button */ - class Button : public Widget - { - public: - virtual ~Button() = default; - - public: - std::string clickOn() const override + class Widget { - return "Click on: Button\n"; - } - }; + public: + virtual ~Widget() = default; + virtual std::string clickOn() const = 0; + }; - class ButtonWindows : public Button - { - public: - std::string clickOn() const override + /* Concrete variations for Button */ + class Button : public Widget { - return "[Linux]" + Button::clickOn(); - } - }; - - class ButtonLinux : public Button - { - public: - std::string clickOn() const override - { - return "[Windows]" + Button::clickOn(); - } - }; + public: + virtual ~Button() = default; - /* Concrete variations for Label */ - class Label : public Widget - { - public: - virtual ~Label() = default; + public: + std::string clickOn() const override + { + return "Click on: Button\n"; + } + }; - public: - std::string clickOn() const override + class ButtonWindows : public Button { - return "Click on: Label\n"; - } - }; - - class LabelWindows : public Label - { - public: - std::string clickOn() const override + public: + std::string clickOn() const override + { + return "[Linux]" + Button::clickOn(); + } + }; + + class ButtonLinux : public Button { - return "[Windows]" + Label::clickOn(); - } - }; - - class LabelLinux : public Label - { - public: - std::string clickOn() const override + public: + std::string clickOn() const override + { + return "[Windows]" + Button::clickOn(); + } + }; + + /* Concrete variations for Label */ + class Label : public Widget { - return "[Linux]" + Label::clickOn(); - } - }; + public: + virtual ~Label() = default; - /* Concrete variations for others widgets like Text,CCombo or new platform macOS etc*/ - // [Problem 1] We have to write the Text/TextLinux ... + public: + std::string clickOn() const override + { + return "Click on: Label\n"; + } + }; - namespace Client - { - void clientCode(const Widget *widget) + class LabelWindows : public Label { - if (widget != nullptr) - std::cout << widget->clickOn(); - } - } - - void run() - { - // [Problem 2] : Use the Bridge if you need to be able to switch implementations at runtime. how to exmaple for this - // still don't know - Widget *button = new ButtonWindows(); - Client::clientCode(button); - delete button; - } -} + public: + std::string clickOn() const override + { + return "[Windows]" + Label::clickOn(); + } + }; + + class LabelLinux : public Label + { + public: + std::string clickOn() const override + { + return "[Linux]" + Label::clickOn(); + } + }; -namespace BridgePattern -{ - /** - * The Implementation defines the interface for all implementation classes. It - * doesn't have to match the Abstraction's interface. In fact, the two - * interfaces can be entirely different. Typically the Implementation interface - * provides only primitive Widgets, while the Abstraction defines higher- - * level Widgets based on those primitives. - */ - class OsImplemetation - { - public: - virtual std::string clickOnImplement() const = 0; - virtual ~OsImplemetation() = default; - }; + /* Concrete variations for others widgets like Text,CCombo or new platform macOS etc*/ + // [Problem 1] We have to write the Text/TextLinux ... - class WindowsImplemetation : public OsImplemetation - { - public: - std::string clickOnImplement() const override + namespace Client { - return "[Windows]"; + void clientCode(const Widget *widget) + { + if (widget != nullptr) + std::cout << widget->clickOn(); + } } - }; - class LinuxImplemetation : public OsImplemetation - { - public: - std::string clickOnImplement() const override + void run() { - return "[Linux]"; + // [Problem 2] : Use the Bridge if you need to be able to switch implementations at runtime. how to exmaple for this + // still don't know + Widget *button = new ButtonWindows(); + Client::clientCode(button); + delete button; } - }; + } - /** - * The Abstraction defines the interface for the "control" part of the two class - * hierarchies. It maintains a reference to an object of the Implementation - * hierarchy and delegates all of the real work to this object. - */ - class WidgetAbstraction + namespace BridgePattern { - protected: - OsImplemetation *_implementation; - - public: - explicit WidgetAbstraction(OsImplemetation *implemetation) : _implementation{implemetation} + /** + * The Implementation defines the interface for all implementation classes. It + * doesn't have to match the Abstraction's interface. In fact, the two + * interfaces can be entirely different. Typically the Implementation interface + * provides only primitive Widgets, while the Abstraction defines higher- + * level Widgets based on those primitives. + */ + class OsImplemetation { - } - virtual ~WidgetAbstraction() = default; - - virtual std::string clickOn() const = 0; - }; + public: + virtual std::string clickOnImplement() const = 0; + virtual ~OsImplemetation() = default; + }; - /** - * We can extend the Abstraction without changing the Implementation classes. - */ - class ButtonAbstraction : public WidgetAbstraction - { - public: - explicit ButtonAbstraction(OsImplemetation *implemetation) : WidgetAbstraction{implemetation} {} - std::string clickOn() const override + class WindowsImplemetation : public OsImplemetation { - return this->_implementation->clickOnImplement() + "Click on: Button\n"; - } - }; - - class LabelAbstraction : public WidgetAbstraction - { - public: - explicit LabelAbstraction(OsImplemetation *implemetation) : WidgetAbstraction{implemetation} {} - std::string clickOn() const override + public: + std::string clickOnImplement() const override + { + return "[Windows]"; + } + }; + + class LinuxImplemetation : public OsImplemetation { - return this->_implementation->clickOnImplement() + "Click on: Label\n"; - } - }; - - namespace Client - { - void clientCode(const WidgetAbstraction *widget) + public: + std::string clickOnImplement() const override + { + return "[Linux]"; + } + }; + + /** + * The Abstraction defines the interface for the "control" part of the two class + * hierarchies. It maintains a reference to an object of the Implementation + * hierarchy and delegates all of the real work to this object. + */ + class WidgetAbstraction { - if (widget != nullptr) - std::cout << widget->clickOn(); + protected: + OsImplemetation *_implementation; + + public: + explicit WidgetAbstraction(OsImplemetation *implemetation) : _implementation{implemetation} + { + } + virtual ~WidgetAbstraction() = default; + + virtual std::string clickOn() const = 0; + }; + + /** + * We can extend the Abstraction without changing the Implementation classes. + */ + class ButtonAbstraction : public WidgetAbstraction + { + public: + explicit ButtonAbstraction(OsImplemetation *implemetation) : WidgetAbstraction{implemetation} {} + std::string clickOn() const override + { + return this->_implementation->clickOnImplement() + "Click on: Button\n"; + } + }; + + class LabelAbstraction : public WidgetAbstraction + { + public: + explicit LabelAbstraction(OsImplemetation *implemetation) : WidgetAbstraction{implemetation} {} + std::string clickOn() const override + { + return this->_implementation->clickOnImplement() + "Click on: Label\n"; + } + }; + + namespace Client + { + void clientCode(const WidgetAbstraction *widget) + { + if (widget != nullptr) + std::cout << widget->clickOn(); + } } - } - void run() - { - // TODO: check memory leak here - OsImplemetation *os = new WindowsImplemetation(); - WidgetAbstraction *widget = new ButtonAbstraction(os); - Client::clientCode(widget); + void run() + { + // TODO: check memory leak here + OsImplemetation *os = new WindowsImplemetation(); + WidgetAbstraction *widget = new ButtonAbstraction(os); + Client::clientCode(widget); - os = new LinuxImplemetation(); - widget = new LabelAbstraction(os); - Client::clientCode(widget); + os = new LinuxImplemetation(); + widget = new LabelAbstraction(os); + Client::clientCode(widget); - delete os; - delete widget; + delete os; + delete widget; + } } -} -struct BridgeAutoruner -{ - BridgeAutoruner() + struct BridgeAutoruner { - std::cout << "\n--- Bridge Pattern Example ---\n"; - Problem::run(); - BridgePattern::run(); - } -}; + BridgeAutoruner() + { + std::cout << "\n--- Bridge Pattern Example ---\n"; + Problem::run(); + BridgePattern::run(); + } + }; -static BridgeAutoruner instance; \ No newline at end of file + static BridgeAutoruner instance; +} \ No newline at end of file diff --git a/src/patterns/structural/Proxy.cpp b/src/patterns/structural/Proxy.cpp index 8e71f1d..be12cc4 100644 --- a/src/patterns/structural/Proxy.cpp +++ b/src/patterns/structural/Proxy.cpp @@ -3,253 +3,255 @@ // UML: docs/uml/patterns_structural_proxy.drawio.svg #include - -namespace Problem +namespace { - const std::string admin = "admin"; - - class IServer - { - public: - virtual ~IServer() = default; - virtual void request1() = 0; - virtual void request2() = 0; - virtual void request3() = 0; - }; - - class Server : public IServer + namespace Problem { - private: - std::string _id; + const std::string admin = "admin"; - public: - explicit Server(const std::string &id) : _id{id} + class IServer { - // [P1] Heavy or complex construction, so ideally should be lazy-loaded - std::cout << "[Server] Constructor: " << _id << "\n"; - } - - // [P2] Need access control - // [P3] Need to log requests without modifying the Server itself - void request1() override + public: + virtual ~IServer() = default; + virtual void request1() = 0; + virtual void request2() = 0; + virtual void request3() = 0; + }; + + class Server : public IServer { - if (_id != admin) + private: + std::string _id; + + public: + explicit Server(const std::string &id) : _id{id} { - std::cout << "[Server] Invalid ID: " << _id << "\n"; - return; + // [P1] Heavy or complex construction, so ideally should be lazy-loaded + std::cout << "[Server] Constructor: " << _id << "\n"; } - std::cout << "[Server] Handling request-1 for: " << _id << "\n"; - } - void request2() override - { - if (_id != admin) + // [P2] Need access control + // [P3] Need to log requests without modifying the Server itself + void request1() override { - std::cout << "[Server] Invalid ID: " << _id << "\n"; - return; + if (_id != admin) + { + std::cout << "[Server] Invalid ID: " << _id << "\n"; + return; + } + std::cout << "[Server] Handling request-1 for: " << _id << "\n"; } - std::cout << "[Server] Handling request-2 for: " << _id << "\n"; - } - void request3() override - { - if (_id != admin) + void request2() override { - std::cout << "[Server] Invalid ID: " << _id << "\n"; - return; + if (_id != admin) + { + std::cout << "[Server] Invalid ID: " << _id << "\n"; + return; + } + std::cout << "[Server] Handling request-2 for: " << _id << "\n"; } - std::cout << "[Server] Handling request-3 for: " << _id << "\n"; - } - }; - namespace Client - { - void clientCode(IServer *s) - { - if (s != nullptr) + void request3() override { - s->request1(); - s->request2(); - s->request3(); + if (_id != admin) + { + std::cout << "[Server] Invalid ID: " << _id << "\n"; + return; + } + std::cout << "[Server] Handling request-3 for: " << _id << "\n"; } - } - } - - void run() - { - std::cout << "\n\n"; + }; + namespace Client { - std::string connectionId = "admin"; - // [P4] The Server is constructed immediately even if we do not call any requests - IServer *server = new Server(connectionId); - std::cout << "User request\n"; - Client::clientCode(server); - delete server; + void clientCode(IServer *s) + { + if (s != nullptr) + { + s->request1(); + s->request2(); + s->request3(); + } + } } + void run() { - // [P4] Server is constructed even for invalid ID, wasting resources - std::string invalidId = "xxx"; - Server *server = new Server(invalidId); - Client::clientCode(server); - delete server; - } - } -} + std::cout << "\n\n"; -namespace ProxyPattern -{ - const std::string admin = "admin"; + { + std::string connectionId = "admin"; + // [P4] The Server is constructed immediately even if we do not call any requests + IServer *server = new Server(connectionId); + std::cout << "User request\n"; + Client::clientCode(server); + delete server; + } - class IServer - { - public: - virtual ~IServer() = default; - virtual void request1() = 0; - virtual void request2() = 0; - virtual void request3() = 0; - }; + { + // [P4] Server is constructed even for invalid ID, wasting resources + std::string invalidId = "xxx"; + Server *server = new Server(invalidId); + Client::clientCode(server); + delete server; + } + } + } - class Server : public IServer + namespace ProxyPattern { - private: - std::string _id; + const std::string admin = "admin"; - public: - explicit Server(const std::string &id) : _id{id} + class IServer { - std::cout << "[Server] Constructor: " << _id << "\n"; - } - - void request1() override + public: + virtual ~IServer() = default; + virtual void request1() = 0; + virtual void request2() = 0; + virtual void request3() = 0; + }; + + class Server : public IServer { - std::cout << "[Server] Handling request-1 for: " << _id << "\n"; - } + private: + std::string _id; - void request2() override - { - std::cout << "[Server] Handling request-2 for: " << _id << "\n"; - } + public: + explicit Server(const std::string &id) : _id{id} + { + std::cout << "[Server] Constructor: " << _id << "\n"; + } - void request3() override - { - std::cout << "[Server] Handling request-3 for: " << _id << "\n"; - } - }; + void request1() override + { + std::cout << "[Server] Handling request-1 for: " << _id << "\n"; + } - class ServerProxy : public IServer - { - private: - std::string _id; - Server *_server; + void request2() override + { + std::cout << "[Server] Handling request-2 for: " << _id << "\n"; + } + + void request3() override + { + std::cout << "[Server] Handling request-3 for: " << _id << "\n"; + } + }; - bool checkAccess() + class ServerProxy : public IServer { - std::cout << "[Proxy] Checking access before forwarding request.\n"; - if (_id != admin) + private: + std::string _id; + Server *_server; + + bool checkAccess() { - return false; + std::cout << "[Proxy] Checking access before forwarding request.\n"; + if (_id != admin) + { + return false; + } + + // Lazy initialization: construct Server only on first access + if (_server == nullptr) + { + _server = new Server(_id); + } + return true; } - // Lazy initialization: construct Server only on first access - if (_server == nullptr) + void logAccess() const { - _server = new Server(_id); + std::cout << "[Proxy] Logging request time: " << _id << " .\n"; } - return true; - } - void logAccess() const - { - std::cout << "[Proxy] Logging request time: " << _id << " .\n"; - } + public: + explicit ServerProxy(const std::string &id) : _id{id}, _server{nullptr} + { + std::cout << "[Proxy] Constructor: " << _id << "\n"; + } - public: - explicit ServerProxy(const std::string &id) : _id{id}, _server{nullptr} - { - std::cout << "[Proxy] Constructor: " << _id << "\n"; - } + ~ServerProxy() + { + std::cout << "[Proxy] Destructor: " << _id << "\n"; + if (_server != nullptr) + { + delete _server; + } + } - ~ServerProxy() - { - std::cout << "[Proxy] Destructor: " << _id << "\n"; - if (_server != nullptr) + void request1() override { - delete _server; + if (checkAccess()) + { + _server->request1(); + logAccess(); + } } - } - void request1() override - { - if (checkAccess()) + void request2() override { - _server->request1(); - logAccess(); + if (checkAccess()) + { + _server->request2(); + logAccess(); + } } - } - void request2() override - { - if (checkAccess()) + void request3() override { - _server->request2(); - logAccess(); + if (checkAccess()) + { + _server->request3(); + logAccess(); + } } - } + }; - void request3() override + namespace Client { - if (checkAccess()) + void clientCode(IServer *s) { - _server->request3(); - logAccess(); + if (s != nullptr) + { + s->request1(); + s->request2(); + s->request3(); + } } } - }; - namespace Client - { - void clientCode(IServer *s) + void run() { - if (s != nullptr) + std::cout << "\n\n"; + { - s->request1(); - s->request2(); - s->request3(); + std::string connectionId = "admin"; + // Server is not constructed until first request is made + IServer *server = new ServerProxy(connectionId); + std::cout << "User request\n"; + Client::clientCode(server); + delete server; } - } - } - - void run() - { - std::cout << "\n\n"; - { - std::string connectionId = "admin"; - // Server is not constructed until first request is made - IServer *server = new ServerProxy(connectionId); - std::cout << "User request\n"; + // Server is not constructed if id is invalid + std::string invalidId = "xxx"; + Server *server = new Server(invalidId); Client::clientCode(server); delete server; } - - // Server is not constructed if id is invalid - std::string invalidId = "xxx"; - Server *server = new Server(invalidId); - Client::clientCode(server); - delete server; } -} -struct ProxyAutoRunner -{ - ProxyAutoRunner() + struct ProxyAutoRunner { - std::cout << "\n--- Proxy Pattern Example ---\n"; - Problem::run(); - ProxyPattern::run(); - } -}; + ProxyAutoRunner() + { + std::cout << "\n--- Proxy Pattern Example ---\n"; + Problem::run(); + ProxyPattern::run(); + } + }; -static ProxyAutoRunner instance; \ No newline at end of file + static ProxyAutoRunner instance; +}