Created
November 11, 2023 02:14
-
-
Save srele96/bdd812885d8518e466cf9afd588ab0fe to your computer and use it in GitHub Desktop.
Observer, Design Pattern, C++, Implementation, Virtual Method, Inheritance
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <algorithm> | |
#include <functional> | |
#include <iostream> | |
#include <memory> | |
#include <string> | |
#include <vector> | |
// Problem: Stock Price Alert System | |
// | |
// Description: | |
// | |
// You are tasked with designing a stock price alert system using the Observer | |
// design pattern in C++. The system will have the following components: | |
// | |
// - Stock: This class represents a stock in the market. It should have | |
// attributes like stock name and price. | |
// - StockMarket: This class manages a collection of Stock objects. It | |
// should allow adding and updating stock prices. | |
// - Observer Interface: This interface should define the method that all | |
// observers must implement to receive updates. | |
// - DisplayBoard and AlertSystem: Two concrete classes that implement the | |
// Observer interface. DisplayBoard displays the latest stock prices, and | |
// AlertSystem sends alerts when a stock price reaches a certain threshold. | |
// | |
// Requirements: | |
// | |
// - Implement an Observer interface with an update() method. | |
// - Stock should be a class with properties for the name and price of the | |
// stock. It should notify all observers whenever its price changes. | |
// - StockMarket should be able to add new stocks and update the prices of | |
// existing stocks. | |
// - DisplayBoard and AlertSystem should both implement the Observer | |
// interface. DisplayBoard should display the latest prices of stocks, and | |
// AlertSystem should check for price thresholds and send alerts. | |
// - The system should support multiple DisplayBoard and AlertSystem | |
// instances observing the same stocks. | |
// - When the price of a stock changes, all registered observers should be | |
// notified. | |
// | |
// Example: | |
// | |
// Suppose the StockMarket has two stocks: Apple (AAPL) and Google (GOOGL). Two | |
// DisplayBoard instances and one AlertSystem are observing these stocks. When | |
// the price of Apple stock changes, both DisplayBoard instances should update | |
// the display, and the AlertSystem should check if the new price crosses a | |
// predefined threshold and, if so, trigger an alert. | |
class Stock; | |
class IObserver { | |
public: | |
virtual void OnUpdate(const Stock &stock) = 0; | |
virtual ~IObserver() = default; | |
}; | |
class ISubject { | |
public: | |
virtual void AddObserver(const std::shared_ptr<IObserver> &observer) = 0; | |
virtual void NotifyObservers() = 0; | |
virtual ~ISubject() = default; | |
}; | |
class Stock : public ISubject { | |
private: | |
static int IDCounter; | |
int id_; | |
int price_; | |
std::string name_; | |
std::vector<std::weak_ptr<IObserver>> observers_; | |
public: | |
Stock() : id_{IDCounter++} {} | |
Stock(std::string name, int price) | |
: id_{IDCounter++}, name_{std::move(name)}, price_{price} {} | |
auto ID() const -> int { return id_; } | |
void Name(std::string name) { name_ = std::move(name); } | |
auto Name() const -> std::string { return name_; } | |
void Price(int price) { | |
price_ = price; | |
NotifyObservers(); | |
} | |
auto Price() const -> int { return price_; } | |
void AddObserver(const std::shared_ptr<IObserver> &observer) override { | |
observers_.push_back(observer); | |
} | |
void NotifyObservers() override { | |
for (std::weak_ptr<IObserver> &observer : observers_) { | |
if (std::shared_ptr<IObserver> ptr_observer = observer.lock()) { | |
ptr_observer->OnUpdate(*this); | |
} | |
} | |
} | |
// Thanks to the observable pattern we can observe constructing, copying, | |
// moving, assigning, destroying, etc... of the Stock class. | |
}; | |
class DisplayBoard : public IObserver { | |
private: | |
std::reference_wrapper<std::ostream> display_; | |
public: | |
DisplayBoard(std::ostream &display) : display_{display} {} | |
void OnUpdate(const Stock &stock) override { | |
display_.get() << stock.ID() << ": " << stock.Name() << " - " | |
<< stock.Price() << "\n"; | |
} | |
}; | |
class AlertSystem : public IObserver { | |
private: | |
int threshold_; | |
std::reference_wrapper<std::ostream> out_; | |
public: | |
AlertSystem(int threshold, std::ostream &out) | |
: threshold_{threshold}, out_{out} {} | |
void OnUpdate(const Stock &stock) override { | |
if (stock.Price() > threshold_) { | |
out_.get() << stock.ID() << ": " | |
<< "(Alert!) " << stock.Name() << " - " << stock.Price() | |
<< "\n"; | |
} | |
} | |
}; | |
constexpr int InitialIDCounter = 1; | |
int Stock::IDCounter = InitialIDCounter; | |
class StockMarket { | |
private: | |
std::vector<Stock> stocks_; | |
public: | |
void AddStock(const Stock &stock) { stocks_.push_back(stock); } | |
void RemoveStock(const std::function<bool(const Stock &)> &predicate) { | |
stocks_.erase(std::remove_if(stocks_.begin(), stocks_.end(), predicate), | |
stocks_.end()); | |
} | |
void UpdateStock(const std::function<void(Stock &)> &callback) { | |
for (auto &stock : stocks_) { | |
callback(stock); | |
} | |
} | |
}; | |
void RunStockMarket() { | |
std::vector<std::unique_ptr<Stock>> stocks; | |
constexpr int appleStockPrice{100}; | |
constexpr int googleStockPrice{200}; | |
stocks.push_back(std::make_unique<Stock>("Apple", appleStockPrice)); | |
stocks.push_back(std::make_unique<Stock>("Google", googleStockPrice)); | |
std::shared_ptr<IObserver> displayToCout{ | |
std::make_shared<DisplayBoard>(std::cout)}; | |
std::shared_ptr<IObserver> displayToCerr{ | |
std::make_shared<DisplayBoard>(std::cerr)}; | |
constexpr int threshold{150}; | |
std::shared_ptr<IObserver> alertSystem{ | |
std::make_shared<AlertSystem>(threshold, std::cout)}; | |
StockMarket stockMarket; | |
for (std::unique_ptr<Stock> &stock : stocks) { | |
stock->AddObserver(displayToCout); | |
stock->AddObserver(displayToCerr); | |
stock->AddObserver(alertSystem); | |
stockMarket.AddStock(*stock); | |
} | |
stockMarket.UpdateStock([&stocks](Stock &stock) { | |
if (stock.ID() == stocks[0]->ID()) { | |
constexpr int newPrice{150}; | |
stock.Price(newPrice); | |
} | |
}); | |
stockMarket.UpdateStock([&stocks](Stock &stock) { | |
if (stock.ID() == stocks[0]->ID()) { | |
constexpr int newPrice{200}; | |
stock.Price(newPrice); | |
} | |
}); | |
stockMarket.RemoveStock( | |
[&stocks](const Stock &stock) { return stock.ID() == 1; }); | |
stockMarket.UpdateStock([&stocks](Stock &stock) { | |
if (stock.ID() == stocks[1]->ID()) { | |
constexpr int newPrice{250}; | |
stock.Price(newPrice); | |
} | |
}); | |
} | |
auto main() -> int { | |
RunStockMarket(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment