From 99291a32909b859c5bda8ef7e54189d6e5d5e17c Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Tue, 11 Nov 2025 14:13:14 +0700 Subject: [PATCH] Add bridge pattern --- .gitignore | 3 +- CMakeLists.txt | 1 + .../uml/patterns_structural_bridge.drawio.svg | 4 + src/patterns/structural/Bridge.cpp | 207 ++++++++++++++++++ 4 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 docs/uml/patterns_structural_bridge.drawio.svg create mode 100644 src/patterns/structural/Bridge.cpp diff --git a/.gitignore b/.gitignore index b746b06..89dd47f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *build *private* -*.vscode \ No newline at end of file +*.vscode +*Identifier \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index e4d9feb..495f334 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,7 @@ set(APP_SOURCES "src/core/datatypes/class/CConstructors.cpp" "src/core/datatypes/class/CDestructors.cpp" "src/patterns/structural/Adapter.cpp" + "src/patterns/structural/Bridge.cpp" ) # Test files diff --git a/docs/uml/patterns_structural_bridge.drawio.svg b/docs/uml/patterns_structural_bridge.drawio.svg new file mode 100644 index 0000000..00b262f --- /dev/null +++ b/docs/uml/patterns_structural_bridge.drawio.svg @@ -0,0 +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 diff --git a/src/patterns/structural/Bridge.cpp b/src/patterns/structural/Bridge.cpp new file mode 100644 index 0000000..796d08d --- /dev/null +++ b/src/patterns/structural/Bridge.cpp @@ -0,0 +1,207 @@ +#include + +namespace Problem +{ + class Widget + { + 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 + { + return "Click on: Button\n"; + } + }; + + class ButtonWindows : public Button + { + public: + std::string clickOn() const override + { + return "[Linux]" + Button::clickOn(); + } + }; + + class ButtonLinux : public Button + { + public: + std::string clickOn() const override + { + return "[Windows]" + Button::clickOn(); + } + }; + + /* Concrete variations for Label */ + class Label : public Widget + { + public: + virtual ~Label() = default; + + public: + std::string clickOn() const override + { + return "Click on: Label\n"; + } + }; + + class LabelWindows : public Label + { + public: + std::string clickOn() const override + { + return "[Windows]" + Label::clickOn(); + } + }; + + class LabelLinux : public Label + { + public: + std::string clickOn() const override + { + return "[Linux]" + Label::clickOn(); + } + }; + + /* Concrete variations for others widgets like Text,CCombo or new platform macOS etc*/ + // [Problem 1] We have to write the Text/TextLinux ... + + namespace Client + { + void clientCode(const Widget *widget) + { + 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; + } +} + +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; + }; + + class WindowsImplemetation : public OsImplemetation + { + public: + std::string clickOnImplement() const override + { + return "[Windows]"; + } + }; + + class LinuxImplemetation : public OsImplemetation + { + 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 + { + 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); + + os = new LinuxImplemetation(); + widget = new LabelAbstraction(os); + Client::clientCode(widget); + + delete os; + delete widget; + } +} + +struct BridgeAutoruner +{ + BridgeAutoruner() + { + std::cout << "\n--- Bridge Pattern Example ---\n"; + Problem::run(); + BridgePattern::run(); + } +}; + +static BridgeAutoruner instance; \ No newline at end of file