- C++ Home
- C++ Overview
- C++ Environment Setup
- C++ Basic Syntax
- C++ Comments
- C++ Hello World
- C++ Omitting Namespace
- C++ Tokens
- C++ Constants/Literals
- C++ Keywords
- C++ Identifiers
- C++ Data Types
- C++ Numeric Data Types
- C++ Character Data Type
- C++ Boolean Data Type
- C++ Variable Types
- C++ Variable Scope
- C++ Multiple Variables
- C++ Input Output Operations
- C++ Basic Input/Output
- C++ Cin
- C++ Cout
- C++ Manipulators
- Type System & Data Representation
- C++ Modifier Types
- C++ Storage Classes
- C++ Constexpr Specifier
- C++ Numbers
- C++ Enumeration
- C++ Enum Class
- C++ References
- C++ Date & Time
- C++ Operators
- C++ Operators
- C++ Arithmetic Operators
- C++ Relational Operators
- C++ Logical Operators
- C++ Bitwise Operators
- C++ Assignment Operators
- C++ sizeof Operator
- C++ Conditional Operator
- C++ Comma Operator
- C++ Member Operators
- C++ Casting Operators
- C++ Pointer Operators
- C++ Operators Precedence
- C++ Unary Operators
- C++ Scope Resolution Operator
- C++ Control Statements
- C++ Decision Making
- C++ if Statement
- C++ if else Statement
- C++ Nested if Statements
- C++ switch Statement
- C++ Nested switch Statements
- C++ Loop Types
- C++ while Loop
- C++ for Loop
- C++ do while Loop
- C++ Foreach Loop
- C++ Nested Loops
- C++ Jump Statements
- C++ break Statement
- C++ continue Statement
- C++ goto Statement
- C++ Return Values
- C++ Strings
- C++ Strings
- C++ Loop Through a String
- C++ String Length
- C++ String Concatenation
- C++ String Comparison
- C++ Functions
- C++ Functions
- C++ Multiple Function Parameters
- C++ Recursive Function
- C++ Function Overloading
- C++ Function Overriding
- C++ Default Arguments
- C++ Arrays
- C++ Arrays
- C++ Multidimensional Arrays
- C++ Pointer to an Array
- C++ Passing Arrays to Functions
- C++ Return Array from Functions
- C++ Array Decay
- C++ Structure & Union
- C++ Structures
- C++ Unions
- C++ Class and Objects
- C++ Object Oriented
- C++ Classes & Objects
- C++ Class Member Functions
- C++ Class Access Modifiers
- C++ Static Class Members
- C++ Static Data Members
- C++ Static Member Function
- C++ Inline Functions
- C++ this Pointer
- C++ Friend Functions
- C++ Pointer to Classes
- C++ Constructors
- C++ Constructor & Destructor
- C++ Default Constructors
- C++ Parameterized Constructors
- C++ Copy Constructor
- C++ Constructor Overloading
- C++ Constructor with Default Arguments
- C++ Delegating Constructors
- C++ Constructor Initialization List
- C++ Dynamic Initialization Using Constructors
- C++ Destructors
- C++ Virtual Destructor
- C++ Inheritance
- C++ Inheritance
- C++ Multiple Inheritance
- C++ Multilevel Inheritance
- C++ Object-oriented
- C++ Overloading
- C++ Polymorphism
- C++ Abstraction
- C++ Encapsulation
- C++ Interfaces
- C++ Virtual Function
- C++ Pure Virtual Functions & Abstract Classes
- C++ Override Specifiers
- C++ Final Specifiers
- C++ Design Patterns
- C++ Creational Design Patterns
- C++ Singleton Design Pattern
- C++ Factory Method Design Pattern
- C++ Abstract Factory Pattern
- C++ Prototype Design Pattern
- C++ Structural Design Patterns
- C++ Facade Design Pattern
- C++ Iterator Design Pattern
- C++ Mediator Design Pattern
- C++ Memento Design Pattern
- C++ Observer Design Pattern
- C++ State Design Pattern
- C++ File Handling
- C++ Files and Streams
- C++ Reading From File
- C++ Advanced
- C++ Exception Handling
- C++ Dynamic Memory
- C++ Move Semantics
- C++ Namespaces
- C++ Templates
- C++ Preprocessor
- C++ Signal Handling
- C++ Multithreading
- C++ Web Programming
- C++ Socket Programming
- C++ Concurrency
- C++ Advanced Concepts
- C++ Lambda Expression
- C++ nullptr
- C++ unordered_multiset
- C++ Chain of Responsibility
- C++ Structural Design Patterns
- C++ Adapter Pattern
- C++ Bridge Pattern
- C++ Composite Pattern
- C++ Decorator Pattern
- C++ Flyweight Pattern
- C++ Command Pattern
- C++ Proxy Pattern
Observer Design Pattern in C++
Observer Design Pattern is a way to make sure that when something important changes in one part of your program, all the other parts that care about it get updated right away. It's called a one-to-many relationship because one main object (the subject) can have many other objects (the observers) watching it. When the subject changes, it tells all its observers so they can update themselves. This is super helpful when you want different parts of your program to always show the latest information, but you don't want them to be tightly connected or mixed together.
For example, imagine you have a weather app with several display screens showing the current weather. The weather data is the subject, and the display screens are the observers. Whenever the weather changes, the weather data tells all the screens to update, so everyone always sees the newest weather. This way, you don't have to update each screen by hand because they all get the news automatically.
Sometimes people mix up the Observer Design Pattern with the Mediator Design Pattern. The difference is important: in the Observer Pattern, the subject keeps a list of observers and tells them when something changes. In the Mediator Pattern, there's a special mediator object in the middle that helps different objects talk to each other, so they don't talk directly. The Observer Pattern is all about keeping things in sync, while the Mediator Pattern is about organizing communication.
Components of Observer Design Pattern
The Observer Design Pattern consists of the following main components −
- Subject − This is the main object that has some important information or state. When something changes inside the subject, it lets others know about it. The subject keeps a list of all the people (observers) who want to know when something changes. For example, in a weather app, the weather data is the subject because it knows the latest weather and tells others when it changes.
- Observer − An observer is anyone who wants to know when the subject changes. Observers sign up with the subject, and whenever there is an update, the subject tells all its observers. In our weather app example, the display screens are observers because they show the latest weather whenever the weather data changes.
- Concrete Subject − This is a real, working version of the subject. It actually stores the data and knows how to tell the observers when something changes. In the weather app, the WeatherData class is the concrete subject because it keeps the weather info and notifies the displays.
- Concrete Observer − This is a real, working version of an observer. It knows how to react when the subject tells it about a change. In the weather app, the WeatherDisplay class is a concrete observer because it updates what it shows whenever the weather changes.
C++ Implementation of Observer Design Pattern
In this section, we will implement the Observer Design Pattern in C++. We will create a simple weather monitoring application to demonstrate how the pattern works.
Steps to Implement Observer Design Pattern in C++
Follow these steps to implement the Observer Design Pattern in C++:
- First, create an Observer interface. This is like a contract that says every observer must have an
updatefunction. This function will be called whenever there is a change. - Next, make a class for the actual observers (for example, a display screen). This class should use the Observer interface and define what happens when it gets updated (like showing the new weather).
- Now, create a Subject interface. This is a contract for the main object (like the weather data) and says it must have ways to add, remove, and notify observers.
- Then, make a class for the real subject (for example, the weather data). This class should use the Subject interface and keep a list of all observers. When the weather changes, it should tell all observers by calling their
updatefunction. - In your main program, make objects for the subject (weather data) and the observers (display screens).
- Add the observers to the subject's list, then change the weather data to see how all the observers get updated automatically.
Example Code for Observer Design Pattern in C++
Here is a simple implementation of the Observer Design Pattern in C++
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
// Observer interface
class Observer {
public:
virtual void update(float temperature, float humidity, float pressure) = 0;
};
// Concrete Observer class
class WeatherDisplay : public Observer {
private:
float temperature;
float humidity;
float pressure;
public:
void update(float temp, float hum, float pres) override {
temperature = temp;
humidity = hum;
pressure = pres;
display();
}
void display() {
cout << "Weather Update - Temperature: " << temperature
<< ", Humidity: " << humidity
<< ", Pressure: " << pressure << endl;
}
};
// Subject interface
class Subject {
public:
virtual void attach(Observer* observer) = 0;
virtual void detach(Observer* observer) = 0;
virtual void notify() = 0;
};
// Concrete Subject class
class WeatherData : public Subject {
private:
vector<Observer*> observers;
float temperature;
float humidity;
float pressure;
public:
void attach(Observer* observer) override {
observers.push_back(observer);
}
void detach(Observer* observer) override {
observers.erase(remove(observers.begin(), observers.end(), observer), observers.end());
}
void notify() override {
for (Observer* observer : observers) {
observer->update(temperature, humidity, pressure);
}
}
void setMeasurements(float temp, float hum, float pres) {
temperature = temp;
humidity = hum;
pressure = pres;
notify();
}
};
int main() {
WeatherData weatherData;
WeatherDisplay display1;
WeatherDisplay display2;
weatherData.attach(&display1);
weatherData.attach(&display2);
weatherData.setMeasurements(30.5, 65, 1013.1);
weatherData.setMeasurements(28.3, 70, 1012.5);
weatherData.detach(&display1);
weatherData.setMeasurements(25.0, 80, 1011.8);
return 0;
}
Following is the output of the above code −
Weather Update - Temperature: 30.5, Humidity: 65, Pressure: 1013.1 Weather Update - Temperature: 30.5, Humidity: 65, Pressure: 1013.1 Weather Update - Temperature: 28.3, Humidity: 70, Pressure: 1012.5 Weather Update - Temperature: 25.0, Humidity: 80, Pressure: 1011.8
Pros and Cons of Observer Design Pattern
The Observer Design Pattern offers several advantages and disadvantages −
| Pros | Cons |
|---|---|
| The Observer Design Pattern makes it easy to add new observers without changing the existing code. This means your program can grow and change over time without breaking things that already work. | If you forget to remove observers when they are no longer needed, your program might use more memory than necessary. This can cause memory leaks, especially if the subject is destroyed but the observers are still around. |
| The subject and the observers do not need to know much about each other. This makes your code easier to change and maintain because you can update one part without affecting the other. | If the subject changes its state very often, it will notify all observers each time. This can slow down your program if there are many observers or updates. |
| You can add or remove observers while the program is running. This means your program can react to changes and new requirements without stopping or restarting. | Managing the list of observers and making sure everyone gets the right updates can make your code more complicated, especially in big programs. |
| You can use the same observer with different subjects. This helps you avoid writing the same code again and again. | Observers are not always notified in a specific order. If your program depends on the order of updates, this can sometimes cause problems. |
When to use Observer Design Pattern
The Observer Design Pattern is particularly useful in the following scenarios −
- Use the Observer Design Pattern when you have one object that changes, and you want many other objects to know about this change automatically. For example, if you have a weather station and several display screens, you want all screens to show the new weather as soon as it changes.
- This pattern is helpful when you don't know in advance how many things need to be updated. You can add or remove observers (like display screens) at any time, and they will always get the latest information.
- It's also great when you want to keep your code simple and not have the main object (the subject) worry about who needs updates. The subject just sends out the update, and all observers get it automatically.
- If you want to build a system where different parts react to changes or events, like in event-driven programs or notification systems, the Observer Design Pattern makes this easy and keeps everything organized.
Real-World Examples of Observer Design Pattern
Here are some real-world examples where the Observer Design Pattern is used −
- GUI frameworks use this pattern so that when the data model changes, all the UI components (like buttons, labels, or charts) update automatically to show the latest information.
- Event-driven systems let different parts of a program react to things that happen, like a button click or a new message. When the event source changes, all the listeners (observers) get notified and can respond right away.
- On social media platforms, when someone you follow (the subject) posts something new, you (the observer) get an update instantly. This keeps you connected and always up to date with your favorite accounts.
- Stock market apps use this pattern so that whenever a stock price changes, all the investors who are watching that stock get the latest price right away. This helps investors make quick decisions based on real-time data.
- Messaging systems let you subscribe to topics or channels. When a publisher sends a new message, all the subscribers (observers) who are interested in that topic get the message automatically, so nobody misses important updates.
Conclusion
In this chapter, you learned about the Observer Design Pattern, how it works, its good and bad sides, and where it is used in real life. This pattern is very helpful for making programs where changes in one part need to be shared with many other parts, that keeps everything up to date and easy to manage.