Observer Pattern

So, as decided in the introduction post, let us start with the ritual of solving a problem without knowing anything about the pattern.

Problem Statement:

Lily owns a smartphone with an Airtel sim. She resides in Model Town, and in the vicinity there is an Airtel tower, say tower ‘A’. Whenever Lily is near her home, the phone is connected to ‘A’. However, as she starts moving away, in the morning, towards her workplace, the signal received by phone from ‘A’ starts fading away and at a certain distance signal strength diminishes to a minimal point and the phone disconnects. As a developer of the Airtel’s tower ‘A’ software, Airtel wants you to design the release procedure of a phone (gracefully) such that whenever a phone releases, all the threads in the system are notified.

/* Note that I am using ‘Airtel’ only for illustrative purpose here, Airtel may/may not work on these principles. You can read ‘Airtel’ as any ‘ABC’ company for example. */

Getting deeper…

Requirement:

  1. There are multiple threads active at a particular instance of time in the system.
  2. All the active threads store a phone’s context (and may use it in different ways).
  3. Whenever a user releases, trigger an event that notifies all the threads about the release of the user.

First Insight to solving the problem would be to call a notify method in the User class to notify all threads.

Code looks like-

class User{

private:

int users[MAX_NUM_USERS];

public:

void triggerUserRelease(int user){

/*Perform operations related to releasing user*/

thread1.notify(user);

thread2.notify(user);

thread3.notify(user);

}

};

Enhancement Required:

As Airtel increased capabilities, new features were supported, architecture of their software changed and 2 new threads were introduced. Modify the design to notify about user release to these threads as well.

Thought Process…

This is simple. But, it appears that our design is not scalable. Every time a new thread is added or a thread gets deleted, we need to modify this code. Rather, we should design in a manner such that due to changes in threads, any other section of code does not need to be changed (because, the code could become difficult to maintain then).

Idea

Whenever a new thread is created, it registers to the UserRelease process. UserRelease process then notifies all of the registered threads about the Id of the user that released. Simple 🙂

We shall make ‘User’ as an abstract base class with methods to redister, degster, add and notify users. Class UserData shall implement these methods. Class myThreads shall act as base class for all thread classes in the system.

UML class diagram looks likes-

observer1.jpg

Code will look like-

abstract class User {

private:

myThreads observer;

public:

void addUser(int UserId);

void releaseUser(int UserId);

void register(myThreads id);

void notify();

void deRegister(myThreads id);

}

abstract class myThreads{

public:

void create();

void update(int userId);

};

class UserData{

public:

UserData(){

observers = new ArrayList();

}

void addUser(int UserId){

/*Add logic to add a user to a system */

}

void releaseUser(int userId){

/*Add logic to remove a user from the system*/

notify(ueId);

}

void register(myThreads t){

std::lock_guard<std::mutex> lock(mutex);

observers.add(t);

}

void deRegister(myThreads t){

std::lock_guard<std::mutex> lock(mutex);

observers.erase(t);

}

void notify(int userId){

for(int threadId=0;threadId<observers.size();threadId++)

{

observers.get(threadId).update(userId);

}

}

};

class thread1 : public myThreads{

User ob;

public:

myThreads(User userOb){

ob= userOb;

userOb.register(this);

}

void create(){

/*Logic to add thread */

}

void update(int userId){

/*Add Logic to update the status of user as released and act accordingly*/

}

};

This looks perfect!

We learned the ‘Observer Pattern’

Definition: The Observer Pattern allows to:

  1. Define a one-to-many dependency between a subject and many objects .
  2. Subject maintains a list of dependants called observers.
  3. Whenever a state changes, subject notifies all the observers.

Class diagram as given on Wikipedia:-

observer2.png

Advantages:

  1. When there are a lot of dependants, it allows to send data to all dependants without any change in the subject class.

A Perplexing Consequence:

  1. It can lead to Lapsed Listener Problem. It is a memory leak issue which happens when an observer fails to unsubscribe to a subject when it no longer needs to listen. This means that subject maintains a reference to the observer when the observer is no longer alive. This prevents the dead observer from being garbage collected in garbage collected languages. In C++ it will cause dangling pointers to be present that can lead to segmentation faults. A solution to the problem is to use weak references to observers in the subject.

Save

Published by:

Neha Katyal

I am a research enthusiast, a software developer, a passionate writer and a seeker. From researching on various aspects of software design, to designing and developing 4G/5G algorithms, everything excites me. Besides my inclination towards software, I have a strong interest in spirituality. I am a seeker; learning yoga, meditation, aura cleansing, Vedic astrology, reading Vedic scriptures that can bring me closer to the ultimate truth, are a few things that has formed an integral part of my life. Apart from these, writing, reading fiction and sketching are the places where I find my home. I cannot just pass a bookstore, I cannot come out of a storm until I write a poem, I cannot admire an actor/actress until I sketch their portrait. Yes, I can be called as a 'multipotentialite'. I love to learn a lot, travel, imagine, read, write, draw, design, code, engage in dhyana and yog, serve others, spend time with family. Because, I feel, life is all about learning, falling, rising, feeling, enjoying every moment :-)

Categories Software Design1 Comment

One thought on “Observer Pattern”

Leave a comment