Skip to content
-
Observer Pattern | C++ Design Patterns
Last Updated :
04 Sep, 2024
The Observer Pattern is a behavioral design pattern that defines a one-to-many dependency between objects, meaning that when one object (the subject) changes its state, all its dependents (observers) are notified and updated automatically. This pattern is used to build distributed event-handling systems and is a crucial part of many software architectures, including Model-View-Controller (MVC).
Important Topics for the Observer Pattern in C++ Design Patterns
Key Concepts of the Observer Pattern
Before diving into the implementation of the Observer Pattern in C++, let's understand its key components:
- Subject: This is the object that is being observed. It maintains a list of observers and notifies them of state changes.
- Observer: Observers are objects that are interested in the state changes of the subject. They register with the subject to receive updates.
- Concrete Subject: The concrete subject class inherits from the subject interface or class and is responsible for maintaining the state and notifying observers when changes occur.
- Concrete Observer: Concrete observers implement the observer interface or inherit from an observer class. They register themselves with a concrete subject and react to state changes.
Observer Pattern Example in C++:
Problem statement: Suppose you are developing a weather monitoring application, in which multiple weather stations are responsible for collecting weather data, and you want to create a system where multiple displays can show real-time weather updates. When a weather station collects new data, all registered displays should be updated automatically with the latest information.
Below is the implementation of the above example problem in C++:
C++
#include <iostream>
#include <vector>
// Observer interface
class Observer {
public:
virtual void update(float temperature, float humidity, float pressure) = 0;
};
// Subject (WeatherStation) class
class WeatherStation {
private:
float temperature;
float humidity;
float pressure;
std::vector<Observer*> observers;
public:
void registerObserver(Observer* observer) {
observers.push_back(observer);
}
void removeObserver(Observer* observer) {
// You can implement the removal logic if needed.
}
void notifyObservers() {
for (Observer* observer : observers) {
observer->update(temperature, humidity, pressure);
}
}
void setMeasurements(float temp, float hum, float press) {
temperature = temp;
humidity = hum;
pressure = press;
notifyObservers();
}
};
// Concrete Observer
class Display : public Observer {
public:
void update(float temperature, float humidity, float pressure) {
std::cout << "Display: Temperature = " << temperature
<< "°C, Humidity = " << humidity
<< "%, Pressure = " << pressure << " hPa"
<< std::endl;
}
};
int main() {
WeatherStation weatherStation;
// Create displays
Display display1;
Display display2;
// Register displays as observers
weatherStation.registerObserver(&display1);
weatherStation.registerObserver(&display2);
// Simulate weather data updates
weatherStation.setMeasurements(25.5, 60, 1013.2);
weatherStation.setMeasurements(24.8, 58, 1014.5);
return 0;
}
Output:
Display: Temperature = 25.5°C, Humidity = 60%, Pressure = 1013.2 hPa
Display: Temperature = 25.5°C, Humidity = 60%, Pressure = 1013.2 hPa
Display: Temperature = 24.8°C, Humidity = 58%, Pressure = 1014.5 hPa
Display: Temperature = 24.8°C, Humidity = 58%, Pressure = 1014.5 hPa
Code Explaination:
- We defined an Observer interface with an update method that concrete observers must implement to display weather data.
- The WeatherStation class serves as the subject. It maintains the weather data (temperature, humidity, and pressure) and a list of registered observers.
- It provides methods to register, remove, and notify observers, as well as setting measurements and triggering updates.
- The Display class is a concrete observer that implements the update method to display weather data.
- In the main function:
- we create a WeatherStation instance and two Display instances, which act as observers.
- We register the displays with the weather station, and then simulate weather data updates.
Advantages of the Observer Pattern in C++ Design Patterns
- Decoupling: The Observer Pattern promotes loose coupling between subjects and observers. Subjects don't need to know the concrete types of their observers.
- Scalability: You can easily add or remove observers without modifying the subject. This makes it a flexible solution for systems with dynamic requirements.
- Reusability: Observers can be reused in different contexts, provided they adhere to the observer interface or class.
- Event Handling: The pattern is instrumental in event handling systems, such as GUI frameworks, where components need to respond to user actions.
Disadvantages of the Observer Pattern in C++ Design Patterns
- Memory and Performance Overhead: The use of dynamic lists of observers can introduce memory overhead, and notifying many observers can have a performance impact in large-scale systems.
- Order of Notification: The order in which observers are notified might be significant in some cases, but the pattern doesn't inherently guarantee a specific order.
- Unintended Updates: Observers can receive updates even when they are not interested in certain changes, leading to potentially unnecessary processing.
Similar Reads
Modern C++ Design Patterns Tutorial Design patterns in C++ help developers create maintainable, flexible, and understandable code. They encapsulate the expertise and experience of seasoned software architects and developers, making it easier for newer programmers to follow established best practices. What are C++ Design Patterns?A des
7 min read
Creational Software Design Patterns in C++
Factory Method Pattern | C++ Design Patterns Factory Method Pattern provides an interface for creating objects but leaves the actual object instantiation to derived classes. This allows for flexibility in object creation and promotes loose coupling between the client code and the concrete products.Factory Method Pattern | C++ Design PatternsTa
8 min read
Abstract Factory Pattern | C++ Design Patterns Abstract Factory Pattern is a creational design pattern used in object-oriented programming. It provides an interface for creating families of related or dependent objects without specifying their concrete classes. This pattern is a way to encapsulate the creation of objects and ensure that they are
6 min read
Builder Pattern | C++ Design Patterns The builder pattern is defined as a creational design pattern that separates the construction of a complex object from its representation, allowing us to create different representations of an object using the same construction process. It's beneficial when an object has many optional properties or
6 min read
Prototype Pattern | C++ Design Patterns When designing software, it's crucial to make it efficient, easy to reuse, and simple to maintain. One way to achieve these goals is by using design patterns, and one such pattern is the Prototype Pattern. In this article, we'll explore the Prototype Design Pattern in the context of C++. Important T
5 min read
Singleton Pattern | C++ Design Patterns A singleton pattern is a design pattern that ensures that only one instance of a class can exist in the entire program. This means that if you try to create another instance of the class, it will return the same instance that was created earlier. The Singleton pattern is useful when we need to have
11 min read
Structural Software Design Patterns in C++
Adapter Pattern | C++ Design Patterns Adapter Pattern is a structural design pattern used to make two incompatible interfaces work together. It acts as a bridge between two incompatible interfaces, allowing them to collaborate without modifying their source code. This pattern is particularly useful when integrating legacy code or third-
6 min read
Bridge Method | C++ Design Patterns Bridge Pattern is basically a structural design pattern in software engineering or in C++ programming that is used to separate an object's abstraction from its implementation. It is part of the Gang of Four (GoF) design patterns and is particularly useful when we need to avoid a permanent binding be
9 min read
`;
$(commentSectionTemplate).insertBefore(".article--recommended");
}
loadComments();
});
});
function loadComments() {
if ($("iframe[id*='discuss-iframe']").length top_of_element && top_of_screen articleRecommendedTop && top_of_screen articleRecommendedBottom)) {
if (!isfollowingApiCall) {
isfollowingApiCall = true;
setTimeout(function(){
if (loginData && loginData.isLoggedIn) {
if (loginData.userName !== $('#followAuthor').val()) {
is_following();
} else {
$('.profileCard-profile-picture').css('background-color', '#E7E7E7');
}
} else {
$('.follow-btn').removeClass('hideIt');
}
}, 3000);
}
}
});
}
$(".accordion-header").click(function() {
var arrowIcon = $(this).find('.bottom-arrow-icon');
arrowIcon.toggleClass('rotate180');
});
});
window.isReportArticle = false;
function report_article(){
if (!loginData || !loginData.isLoggedIn) {
const loginModalButton = $('.login-modal-btn')
if (loginModalButton.length) {
loginModalButton.click();
}
return;
}
if(!window.isReportArticle){
//to add loader
$('.report-loader').addClass('spinner');
jQuery('#report_modal_content').load(gfgSiteUrl+'wp-content/themes/iconic-one/report-modal.php', {
PRACTICE_API_URL: practiceAPIURL,
PRACTICE_URL:practiceURL
},function(responseTxt, statusTxt, xhr){
if(statusTxt == "error"){
alert("Error: " + xhr.status + ": " + xhr.statusText);
}
});
}else{
window.scrollTo({ top: 0, behavior: 'smooth' });
$("#report_modal_content").show();
}
}
function closeShareModal() {
const shareOption = document.querySelector('[data-gfg-action="share-article"]');
shareOption.classList.remove("hover_share_menu");
let shareModal = document.querySelector(".hover__share-modal-container");
shareModal && shareModal.remove();
}
function openShareModal() {
closeShareModal(); // Remove existing modal if any
let shareModal = document.querySelector(".three_dot_dropdown_share");
shareModal.appendChild(Object.assign(document.createElement("div"), { className: "hover__share-modal-container" }));
document.querySelector(".hover__share-modal-container").append(
Object.assign(document.createElement('div'), { className: "share__modal" }),
);
document.querySelector(".share__modal").append(Object.assign(document.createElement('h1'), { className: "share__modal-heading" }, { textContent: "Share to" }));
const socialOptions = ["LinkedIn", "WhatsApp","Twitter", "Copy Link"];
socialOptions.forEach((socialOption) => {
const socialContainer = Object.assign(document.createElement('div'), { className: "social__container" });
const icon = Object.assign(document.createElement("div"), { className: `share__icon share__${socialOption.split(" ").join("")}-icon` });
const socialText = Object.assign(document.createElement("span"), { className: "share__option-text" }, { textContent: `${socialOption}` });
const shareLink = (socialOption === "Copy Link") ?
Object.assign(document.createElement('div'), { role: "button", className: "link-container CopyLink" }) :
Object.assign(document.createElement('a'), { className: "link-container" });
if (socialOption === "LinkedIn") {
shareLink.setAttribute('href', `https://www.linkedin.com/sharing/share-offsite/?url=${window.location.href}`);
shareLink.setAttribute('target', '_blank');
}
if (socialOption === "WhatsApp") {
shareLink.setAttribute('href', `https://api.whatsapp.com/send?text=${window.location.href}`);
shareLink.setAttribute('target', "_blank");
}
if (socialOption === "Twitter") {
shareLink.setAttribute('href', `https://twitter.com/intent/tweet?url=${window.location.href}`);
shareLink.setAttribute('target', "_blank");
}
shareLink.append(icon, socialText);
socialContainer.append(shareLink);
document.querySelector(".share__modal").appendChild(socialContainer);
//adding copy url functionality
if(socialOption === "Copy Link") {
shareLink.addEventListener("click", function() {
var tempInput = document.createElement("input");
tempInput.value = window.location.href;
document.body.appendChild(tempInput);
tempInput.select();
tempInput.setSelectionRange(0, 99999); // For mobile devices
document.execCommand('copy');
document.body.removeChild(tempInput);
this.querySelector(".share__option-text").textContent = "Copied"
})
}
});
// document.querySelector(".hover__share-modal-container").addEventListener("mouseover", () => document.querySelector('[data-gfg-action="share-article"]').classList.add("hover_share_menu"));
}
function toggleLikeElementVisibility(selector, show) {
document.querySelector(`.${selector}`).style.display = show ? "block" : "none";
}
function closeKebabMenu(){
document.getElementById("myDropdown").classList.toggle("show");
}