Observer design pattern

The Observer pattern is a design pattern that facilitates communication between objects in a system. It is a behavioral pattern that allows an object, called the subject, to notify other objects, called observers, of any state changes it undergoes. In this article, we will explore the Observer pattern in more detail, including how it works, its advantages and limitations, and a sample code implementation.

How does the Observer pattern work?

The Observer pattern consists of two main components: the subject and the observers. The subject is the object that is being observed, while the observers are the objects that receive notifications when the subject's state changes. The subject maintains a list of its observers, and when its state changes, it notifies all the observers by calling a method on each observer.

In practice, the Observer pattern can be implemented using various programming constructs such as interfaces, abstract classes, and event listeners. In this example, we will use an interface to define the subject and observer objects.

?___________________? ? ? ? ? ? ______________________ 
|? ? ? ? ? ? ? ? ? ?|? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? |
|? ? Subject? ? ? ? |<>--------|? ? ?Observer? ? ? ? ?|
|___________________|? ? ? ? ? |______________________|
|? ? ? ? ? ? ? ? ? ?|? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? |
| + attach(observer)|? ? ? ? ? | + update()? ? ? ? ? ?|
| + detach(observer)|? ? ? ? ? |______________________|
| + notify()? ? ? ? |
|___________________|
        

  • Subject: Maintains a list of observers and sends notifications to them when its state changes.
  • Observer: Defines an interface for objects that should be notified of changes in the Subject's state.
  • ConcreteSubject: Implements the Subject interface and keeps track of its observers. Sends notifications to its observers when its state changes.
  • ConcreteObserver: Implements the Observer interface and receives notifications from the Subject when its state changes.

Example Code

Let's consider a simple example of a weather station that provides weather information to its subscribers. The weather station is the subject, while the subscribers are the observers. The weather station periodically updates its weather information, and it needs to notify its subscribers of these updates.

C++ code:

#include <iostream>
#include <vector>
#include <algorithm>


using namespace std;


// Observer interface
class WeatherObserver {
public:
? ? virtual void update(float temperature, float humidity, float pressure) = 0;
? ? virtual ~WeatherObserver() {}
};




// Subject interface
class WeatherStation {
public:
? ? virtual void subscribe(WeatherObserver* observer) = 0;
? ? virtual void unsubscribe(WeatherObserver* observer) = 0;
? ? virtual void notifyObservers() = 0;
	virtual void updateWeather(float temperature, float humidity, float pressure) = 0;
? ? virtual ~WeatherStation() {}
};




// WeatherStation implementation
class WeatherStationImpl : public WeatherStation {
private:
? ? std::vector<WeatherObserver*> observers;
? ? float temperature;
? ? float humidity;
? ? float pressure;

public:
? ? void subscribe(WeatherObserver* observer) {
? ? ? ? observers.push_back(observer);
? ? }

? ? void unsubscribe(WeatherObserver* observer) {
? ? ? ? observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
? ? }

? ? void notifyObservers() {
? ? ? ? for (WeatherObserver* observer : observers) {
? ? ? ? ? ? observer->update(temperature, humidity, pressure);
? ? ? ? }
? ? }

? ? void updateWeather(float temperature, float humidity, float pressure) {
? ? ? ? this->temperature = temperature;
? ? ? ? this->humidity = humidity;
? ? ? ? this->pressure = pressure;
? ? ? ? notifyObservers();
? ? }
};

// Observer implementation
class WeatherSubscriber : public WeatherObserver {
private:
? ? std::string name;

public:
? ? WeatherSubscriber(std::string name) : name(name) {}

? ? void update(float temperature, float humidity, float pressure) {
? ? ? ? std::cout << name << ": temperature = " << temperature << ", humidity = " << humidity
? ? ? ? ? ? ? ? ? << ", pressure = " << pressure << std::endl;
? ? }
}; 


int main() {
? ? WeatherStation* weatherStation = new WeatherStationImpl();?
? ? WeatherObserver* subscriber11 = new WeatherSubscriber("Subscriber 11");
? ? WeatherObserver* subscriber12 = new WeatherSubscriber("Subscriber 12");

? ? weatherStation->subscribe(subscriber11);
? ? weatherStation->subscribe(subscriber12);

? ? weatherStation->updateWeather(25.5f, 70.2f, 1013.5f);

? ? weatherStation->unsubscribe(subscriber12);

? ? weatherStation->updateWeather(26.0f, 68.7f, 1015.5f);

? ? delete subscriber11;
? ? delete subscriber12;
? ? delete weatherStation;
? ? return 0;
}
 
/*
amit@DESKTOP-9LTOFUP:~/OmPracticeC++$ ./a.out
Subscriber 11: temperature = 25.5, humidity = 70.2, pressure = 1013.5
Subscriber 12: temperature = 25.5, humidity = 70.2, pressure = 1013.5
Subscriber 11: temperature = 26, humidity = 68.7, pressure = 1015.5 
*/        

Kotlin Code:

// Subject interface
interface WeatherStation {
? ? fun subscribe(observer: WeatherObserver)
? ? fun unsubscribe(observer: WeatherObserver)
? ? fun notifyObservers()
}


// Observer interface
interface WeatherObserver {
? ? fun update(temperature: Float, humidity: Float, pressure: Float)
}


// WeatherStation implementation
class WeatherStationImpl : WeatherStation {
? ? private val observers: MutableList<WeatherObserver> = mutableListOf()
? ? private var temperature: Float = 0.0f
? ? private var humidity: Float = 0.0f
? ? private var pressure: Float = 0.0f


? ? override fun subscribe(observer: WeatherObserver) {
? ? ? ? observers.add(observer)
? ? }


? ? override fun unsubscribe(observer: WeatherObserver) {
? ? ? ? observers.remove(observer)
? ? }


? ? override fun notifyObservers() {
? ? ? ? observers.forEach { it.update(temperature, humidity, pressure) }
? ? }


? ? fun updateWeather(temperature: Float, humidity: Float, pressure: Float) {
? ? ? ? this.temperature = temperature
? ? ? ? this.humidity = humidity
? ? ? ? this.pressure = pressure
? ? ? ? notifyObservers()
? ? }
}


// Observer implementation
class WeatherSubscriber(private val name: String) : WeatherObserver {
? ? override fun update(temperature: Float, humidity: Float, pressure: Float) {
? ? ? ? println("$name: temperature = $temperature, humidity = $humidity, pressure = $pressure")
? ? }
}        

In the above code, we define two interfaces: WeatherStation and WeatherObserver. The WeatherStation interface defines the methods that the subject object must implement, while the WeatherObserver interface defines the methods that the observer objects must implement.

We then define two classes: WeatherStationImpl and WeatherSubscriber. The WeatherStationImpl class implements the WeatherStation interface, and it maintains a list of observers. It also has a method to update the weather information, which it does by changing the temperature, humidity, and pressure fields, and then calling the notifyObservers() method.

The WeatherSubscriber class implements the WeatherObserver interface. It has a method called update() that is called when the subject notifies it of a state change. In this case, the update() method simply prints the weather information to the console.

Advantages of the Observer pattern

  • Loose coupling: The observer pattern promotes loose coupling between objects, meaning that the subject and observers can be developed and modified independently.
  • Separation of concerns: The pattern separates the core business logic (the subject) from the presentation logic (the observers), which makes it easier to maintain and modify both components independently.
  • Flexibility and reusability: The pattern is flexible and reusable, making it easier to add new observers or subjects to the system without impacting the rest of the code.

Limitations of Observer pattern:

  • Performance overhead: The pattern can create performance overhead when there are a large number of observers attached to a subject, as the subject needs to notify all observers whenever a change occurs.
  • Unintended updates: The pattern may result in unintended updates, as observers are notified of changes in the subject whether or not they actually care about the change.
  • Memory leaks: If the observers are not properly managed and unregistered from the subject, it can lead to memory leaks and impact the performance of the system.

Some of the application of observer pattern :

The Observer pattern is widely used in various software applications where the state of an object needs to be monitored and notified to a set of interested clients in real-time. Here are some examples of applications of the Observer pattern:

  1. Stock Market Applications: In stock market applications, stock prices are continuously changing. Investors who are interested in the stock prices can subscribe to get real-time updates using the Observer pattern.
  2. Traffic Management Systems: In traffic management systems, traffic signals are continuously changing. Vehicles on the road can be seen as observers that need to be notified about the changes in traffic signals.
  3. Social Networking Applications: In social networking applications, users can be considered as observers who need to be notified about the changes in their friends' status, pictures, and other updates.
  4. Gaming Applications: In gaming applications, different game objects need to be updated based on certain events. For example, when a player collects a power-up, other game objects need to be notified to reflect the change.
  5. User Interface Design: The Observer pattern can be used to design user interfaces where the user interacts with different widgets such as buttons, text boxes, etc. Changes in one widget can affect other widgets, which can be updated using the Observer pattern.

These are just a few examples of applications of the Observer pattern. In general, the Observer pattern is used in any system where the state of an object needs to be monitored by multiple clients in real-time.

The Observer Pattern is a powerful and flexible pattern that has many applications in software development. It is commonly used in event-driven systems, user interfaces, and real-time systems where there is a need to track changes in data or events.

Thanks for reading till end , please comment if you have any suggestions.

要查看或添加评论,请登录

Amit Nadiger的更多文章

  • Rust modules

    Rust modules

    Referance : Modules - Rust By Example Rust uses a module system to organize and manage code across multiple files and…

  • List of C++ 17 additions

    List of C++ 17 additions

    1. std::variant and std::optional std::variant: A type-safe union that can hold one of several types, useful for…

  • List of C++ 14 additions

    List of C++ 14 additions

    1. Generic lambdas Lambdas can use auto parameters to accept any type.

    6 条评论
  • Passing imp DS(vec,map,set) to function

    Passing imp DS(vec,map,set) to function

    In Rust, we can pass imp data structures such as , , and to functions in different ways, depending on whether you want…

  • Atomics in C++

    Atomics in C++

    The C++11 standard introduced the library, providing a way to perform operations on shared data without explicit…

    1 条评论
  • List of C++ 11 additions

    List of C++ 11 additions

    1. Smart Pointers Types: std::unique_ptr, std::shared_ptr, and std::weak_ptr.

    2 条评论
  • std::lock, std::trylock in C++

    std::lock, std::trylock in C++

    std::lock - cppreference.com Concurrency and synchronization are essential aspects of modern software development.

    3 条评论
  • std::unique_lock,lock_guard, & scoped_lock

    std::unique_lock,lock_guard, & scoped_lock

    C++11 introduced several locking mechanisms to simplify thread synchronization and prevent race conditions. Among them,…

  • Understanding of virtual & final in C++ 11

    Understanding of virtual & final in C++ 11

    C++ provides powerful object-oriented programming features such as polymorphism through virtual functions and control…

  • Importance of Linux kernal in AOSP

    Importance of Linux kernal in AOSP

    The Linux kernel serves as the foundational layer of the Android Open Source Project (AOSP), acting as the bridge…

    1 条评论

社区洞察

其他会员也浏览了