From 98e3237d377be7b9c2863d541b0ed65c0a10ae3b Mon Sep 17 00:00:00 2001 From: ruinivist Date: Sun, 11 Jan 2026 23:10:47 +0000 Subject: [PATCH] v1 using observer pattern --- .clang-format | 2 + .clangd | 3 + .gitignore | 59 +++++++++++++++++++ subscriber-notifs/CMakeLists.txt | 4 +- .../include/app/inventory_manager.hpp | 20 +++++++ subscriber-notifs/include/app/services.hpp | 22 +++++++ .../include/core/subscribable.hpp | 42 +++++++++++++ subscriber-notifs/include/core/subscriber.hpp | 10 ++++ .../src/app/inventory_manager.cpp | 7 +++ subscriber-notifs/src/app/services.cpp | 21 +++++++ subscriber-notifs/src/main.cpp | 19 ++++++ 11 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 .clang-format create mode 100644 .clangd create mode 100644 .gitignore create mode 100644 subscriber-notifs/include/app/inventory_manager.hpp create mode 100644 subscriber-notifs/include/app/services.hpp create mode 100644 subscriber-notifs/include/core/subscribable.hpp create mode 100644 subscriber-notifs/include/core/subscriber.hpp create mode 100644 subscriber-notifs/src/app/inventory_manager.cpp create mode 100644 subscriber-notifs/src/app/services.cpp create mode 100644 subscriber-notifs/src/main.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..25ed932 --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: Google +IndentWidth: 4 \ No newline at end of file diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..7180be6 --- /dev/null +++ b/.clangd @@ -0,0 +1,3 @@ +CompileFlags: + #C++20 + Add: [-std=c++20] \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..684b757 --- /dev/null +++ b/.gitignore @@ -0,0 +1,59 @@ +# CMake generated files +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake +Makefile +*.cmake +compile_commands.json + +# Build directories +build/ +cmake-build-*/ +out/ +bin/ +lib/ + +# C++ build artifacts +*.o +*.obj +*.exe +*.dll +*.so +*.dylib +*.a +*.lib + +# IDE and editor files +.vscode/settings.json +*.swp +*.swo +*~ +.idea/ +*.sublime-project +*.sublime-workspace + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Temporary files +*.tmp +*.temp +*.log + +# Package files +*.deb +*.rpm +*.tar.gz +*.zip + +# cache +.cache + +# binary +sub_notifs \ No newline at end of file diff --git a/subscriber-notifs/CMakeLists.txt b/subscriber-notifs/CMakeLists.txt index a67303f..672188e 100644 --- a/subscriber-notifs/CMakeLists.txt +++ b/subscriber-notifs/CMakeLists.txt @@ -4,11 +4,11 @@ project(subscriber-notifs VERSION 1.0) set(CMAKE_CXX_STANDARD 20) file(GLOB_RECURSE SRC_FILES "src/*.cpp") -file(GLOB_RECURSE HEADER_FILES "src/*.h" "src/*.hpp") +file(GLOB_RECURSE HEADER_FILES "include/*.hpp") add_executable(sub_notifs ${SRC_FILES} ${HEADER_FILES}) -target_include_directories(sub_notifs PRIVATE ${HEADER_FILES}) +target_include_directories(sub_notifs PRIVATE include ) # from: https://cmake.org/cmake/help/latest/module/FindThreads.html find_package(Threads REQUIRED) diff --git a/subscriber-notifs/include/app/inventory_manager.hpp b/subscriber-notifs/include/app/inventory_manager.hpp new file mode 100644 index 0000000..9584b71 --- /dev/null +++ b/subscriber-notifs/include/app/inventory_manager.hpp @@ -0,0 +1,20 @@ + +#pragma once + +#include +#include + +#include "core/subscribable.hpp" + +using ProductCount = int; +using ProductId = std::string; + +// inventory manager is not generic ( works with the specific types ProductId +// and ProductCount ) but the subscribable is generic +class InventoryManager : public Subscribable { + private: + std::unordered_map inventory_; + + public: + void setInventory(const ProductId& productId, ProductCount quantity); +}; \ No newline at end of file diff --git a/subscriber-notifs/include/app/services.hpp b/subscriber-notifs/include/app/services.hpp new file mode 100644 index 0000000..71f3331 --- /dev/null +++ b/subscriber-notifs/include/app/services.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "app/inventory_manager.hpp" +#include "core/subscriber.hpp" + +class SmsService : public Subscriber { + public: + void onNotification(const ProductId& productId, + const ProductCount& quantity) override; +}; + +class EmailService : public Subscriber { + public: + void onNotification(const ProductId& productId, + const ProductCount& quantity) override; +}; + +class LogService : public Subscriber { + public: + void onNotification(const ProductId& productId, + const ProductCount& quantity) override; +}; \ No newline at end of file diff --git a/subscriber-notifs/include/core/subscribable.hpp b/subscriber-notifs/include/core/subscribable.hpp new file mode 100644 index 0000000..ad9a131 --- /dev/null +++ b/subscriber-notifs/include/core/subscribable.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +#include "subscriber.hpp" + +template +class Subscribable { + using TSubscriber = Subscriber; + + private: + std::unordered_map> subscribersMap_; + + public: + void subscribe(const TEventId& eventId, TSubscriber* subscriber) { + subscribersMap_[eventId].push_back(subscriber); + } + + void unsubscribe(const TEventId& eventId, TSubscriber* subscriber) { + auto entry = subscribersMap_.find(eventId); + if (entry == subscribersMap_.end()) { + return; + } + + std::erase(entry->second, subscriber); + if (entry->second.empty()) { + subscribersMap_.erase(entry); + } + } + + void notify(const TEventId& eventId, const TEventInfo& eventInfo) { + auto entry = subscribersMap_.find(eventId); + if (entry == subscribersMap_.end()) { + return; + } + + for (TSubscriber* subscriber : entry->second) { + subscriber->onNotification(eventId, eventInfo); + } + } +}; \ No newline at end of file diff --git a/subscriber-notifs/include/core/subscriber.hpp b/subscriber-notifs/include/core/subscriber.hpp new file mode 100644 index 0000000..af02316 --- /dev/null +++ b/subscriber-notifs/include/core/subscriber.hpp @@ -0,0 +1,10 @@ +#pragma once + +template +class Subscriber { + public: + virtual void onNotification(const TEventId& eventId, + const TEventInfo& eventInfo) = 0; + + virtual ~Subscriber() = default; +}; \ No newline at end of file diff --git a/subscriber-notifs/src/app/inventory_manager.cpp b/subscriber-notifs/src/app/inventory_manager.cpp new file mode 100644 index 0000000..7962c68 --- /dev/null +++ b/subscriber-notifs/src/app/inventory_manager.cpp @@ -0,0 +1,7 @@ +#include "app/inventory_manager.hpp" + +void InventoryManager::setInventory(const ProductId& productId, + ProductCount quantity) { + inventory_[productId] = quantity; + this->notify(productId, quantity); +} \ No newline at end of file diff --git a/subscriber-notifs/src/app/services.cpp b/subscriber-notifs/src/app/services.cpp new file mode 100644 index 0000000..ead7301 --- /dev/null +++ b/subscriber-notifs/src/app/services.cpp @@ -0,0 +1,21 @@ +#include "app/services.hpp" + +#include + +void SmsService::onNotification(const ProductId& productId, + const ProductCount& quantity) { + std::cout << "SMS Notification - Product: " << productId + << ", Quantity: " << quantity << std::endl; +} + +void EmailService::onNotification(const ProductId& productId, + const ProductCount& quantity) { + std::cout << "Email Notification - Product: " << productId + << ", Quantity: " << quantity << std::endl; +} + +void LogService::onNotification(const ProductId& productId, + const ProductCount& quantity) { + std::cout << "Log Entry - Product: " << productId + << ", Quantity: " << quantity << std::endl; +} \ No newline at end of file diff --git a/subscriber-notifs/src/main.cpp b/subscriber-notifs/src/main.cpp new file mode 100644 index 0000000..65e7368 --- /dev/null +++ b/subscriber-notifs/src/main.cpp @@ -0,0 +1,19 @@ +#include "app/inventory_manager.hpp" +#include "app/services.hpp" + +int main() { + InventoryManager inventoryManager; + + SmsService smsService; + EmailService emailService; + LogService logService; + + inventoryManager.subscribe("ProductA", &smsService); + inventoryManager.subscribe("ProductB", &emailService); + inventoryManager.subscribe("ProductA", &logService); + + inventoryManager.setInventory("ProductA", 100); + inventoryManager.setInventory("ProductB", 200); + + return 0; +} \ No newline at end of file