How to use Observer Design Pattern with Background Thread

How to use Observer Design Pattern with Background Thread

Hello everyone, in this article we are going to talk about How can we use Observer Design Pattern with a background Thread. We are going to make an example with C# language.

Let's get started.

Firstly What is Observer Design Pattern:
In our projects we may need to check status or values of a system or a design. In these cases we use the observer design patterns.

For example, we can talk on a shopping card. When the user add some products to shopping card, this operation updates the count of total products in the card. An observer class observes this opeation and re-count the products in the card then update the variable which hold the count.

For another example, during we drive our cars, an observer component contuniously controls the fuel tanks and update the gauges to display to the driver. Also when the fuel level reach critical level, this observer component starts to warn us. This is also an example of Observer Design Pattern.

Now let's make an example to get this pattern understood.

In our example we are going to build an aircraft structure with its Fuel Quantity and altitude observers. And then we are going to create a background thread to make these observings at background. If there is a critical levels at the values, these observers will warn us and print a message on the console page.
Below image you can see my example schematic:
Observer Design Pattern Example Schematic

Firstly I will create my Observer interface to derive all observer classes with same functions:

IObserver.cs

namespace ObserverPattern_Example
{
    //First we have to create an interface to derive all observer classes
    //All observer classes will have update and Warn Methods 
    //They will update the values and if the value is out of limit,
    //it will warn the user
    interface IObserver
    {
        void Update(int newvalue);
        void Warn();
    }
}

Then I can create my Parameter class.

I will keep all global variables in this class. So I defined them as public static. Because I may need to reach these values from everywhere of the program Here I store the observer indexes in a Dictionary and the other required values. For example I used ObserverIndexes at Program and Aircraft class
AircraftParameters.cs

using System.Collections.Generic;

namespace ObserverPattern_Example
{
    //I will keep all global variables in this class. So I defined them as public static.
    //Because I may need to reach these values from everywhere of the program
    //Here I store the observer indexes in a Dictionary and the other required values.
    //For example I used ObserverIndexes at Program and Aircraft class
    public static class AircraftParameters
    {
        public static Dictionary<string, int> ObserverIndexes = new Dictionary<string, int> {
                { "FuelObserver", 0 }, { "AltiudeObserver", 1 }
            };


        public static int fuelQuantity = 0;
        public static int altitude = 0;
    }
}

Now I can create the observer classes which derived from IObserver interface.

Then I created the Observer classes. My observer classes are derived from Observer Interface. In Update method it will update the related global variable. After updating it will call the warn method, in warn method if the updated value out of limit it will print failure message.

FuelObserver.cs

using System;

namespace ObserverPattern_Example
{
    //Then I created the Observer classes. My observer classes are derived
    //from Observer Interface.

    //In Update method it will update the related global variable.
    //After updating it will call the warn method, in warn method
    //if the updated value out of limit it will print failure message.

    class FuelObserver : IObserver
    {
        public void Update(int newvalue)
        {
            AircraftParameters.fuelQuantity = newvalue;
            this.Warn();
        }

        public void Warn()
        {
            if (AircraftParameters.fuelQuantity < 30)
                Console.WriteLine("FUEL LEVEL IS CRITICAL.. Fuel Level is " + AircraftParameters.fuelQuantity);
            else
                Console.WriteLine("Fuel Level is good " );
        }
    }
}
AltitudeObserver.cs

using System;

namespace ObserverPattern_Example
{
    class AltitudeObserver : IObserver
    {
        //Go FuelObserver class for explanation

        public void Update(int newvalue)
        {
            AircraftParameters.altitude = newvalue;
            this.Warn();
        }

        public void Warn()
        {
            if (AircraftParameters.altitude < 20)
                Console.WriteLine("ALTITUDE IS CRITICAL.. Altitude is " + AircraftParameters.altitude);
            else
                Console.WriteLine("Altitude is good. ");
        }
    }
}

My observers are ready now. I can create my subject class. Let's roll :)

We will call this Aircraft class as subject class. We will observe the values of this system and it will get values from sensores then send the values to the global variables.
I will keep the defined obser classes which derived from interface in an array. This will get easy my task and prevent the confusing. And I will use the BackGroundWorker component from .Net Framework. This component will be started when everything are ready.
I assume these values are getting from sensores and not loaded the //global paameters. They will be sent via BackGroundWorker.
Here is my constructor. I set the observer array at initializations. Here we make configurations of the BackGroundWorker and start it.
This while loop will be re-looped every two seconds. It will not freeze the program. Because it is working at background

Aircraft.cs

using System;
using System.ComponentModel;
using System.Threading;

namespace ObserverPattern_Example
{
    //We will call this Aircraft class as subject class.
    //We will observe the values of this system and it will get values from sensores
    //then send the values to the global variables.
    class Aircraft
    {
        //I will keep the defined obser classes which derived from interface 
        //in an array. This will get easy my task and prevent the confusing.
        IObserver[] observers = new IObserver[AircraftParameters.ObserverIndexes.Count];

        //And I will use the BackGroundWorker component from .Net Framework.
        //This component will be started when everything are ready.
        BackgroundWorker bgw_checkAcParameters = new BackgroundWorker();
 
        //I assume these values are getting from sensores and not loaded the 
        //global paameters. They will be sent via BackGroundWorker.
        private int sensorFuelValue = 0;
        private int sensorAltimeter = 0;

        //Just for debugging :)
        Random rnd = new Random();

        //Here is my constructor. I set the observer array at initializations.
        public Aircraft(IObserver[] _observers)
        {
            observers = _observers;
        }

        //Here we make configurations of the BackGroundWorker and start it.
        public void StartBackgroundObserving()
        {
            bgw_checkAcParameters.WorkerReportsProgress = true;
            bgw_checkAcParameters.WorkerSupportsCancellation = true;
            bgw_checkAcParameters.DoWork += Bgw_checkAcParameters_DoWork;
            bgw_checkAcParameters.RunWorkerAsync();
        }

        //Here is my background workers' task.
        private void Bgw_checkAcParameters_DoWork(object sender, DoWorkEventArgs e)
        {
            //This while loop  will be re-looped every two seconds.
            //It will not freeze the program. Because it is working at background
            while (true)
            {
                //I assume the below variables are getting the datas from sensores. :)
                sensorFuelValue = rnd.Next(0, 100);
                sensorAltimeter = rnd.Next(0, 100);
                //Here I will make the same thing with different values for all
                //observers in the initialized array.
                for (int i = 0; i < observers.Length; i++)
                {
                    //I will check the which observers value and send the data
                    if(i == AircraftParameters.ObserverIndexes["FuelObserver"])
                        this.NotifyObserver(observers[AircraftParameters.ObserverIndexes["FuelObserver"]], sensorFuelValue);
                    else if (i == AircraftParameters.ObserverIndexes["AltiudeObserver"])
                        this.NotifyObserver(observers[AircraftParameters.ObserverIndexes["AltiudeObserver"]], sensorFuelValue);
                }
                 //Here you do not have to use for loop. 
                 //I just want to show a method.
                Thread.Sleep(2000);
            }
        }

        //This function will make the observer updated.
        private void NotifyObserver(IObserver _observer, int _value)
        {
            _observer.Update(_value);
        }
    }
}

And lastly we will start the chain from the Program.cs.

Program.cs

using System;

namespace ObserverPattern_Example
{
    class Program
    {
        //I will initialize the observers in an array and 
        //i will use this array from everywhere at the program
        static IObserver[] observers = new IObserver[AircraftParameters.ObserverIndexes.Count];

        static void Main(string[] args)
        {

            Console.Title = "Observer Design Pattern Example - Thecodeprogram";
            //Then I will inser them with specified indexes
            observers[AircraftParameters.ObserverIndexes["FuelObserver"]] = new FuelObserver();
            observers[AircraftParameters.ObserverIndexes["AltiudeObserver"]] = new AltitudeObserver();

            //Last I will send them to the subject class
            //After Everythig ready I will start the background thread to make observing.
            Aircraft ac = new Aircraft(observers);
            ac.StartBackgroundObserving();

            Console.ReadLine();
        }
    }
}
Our program is ready. Below image you can see the output of the example. Observer Design Pattern Example Output
Important:
My sensor values are coming from random numbers just for debugging.

That is all in this article.

You can Reach the example application on Github : https://github.com/thecodeprogram/ObserverPattern_Example

Have a good Observing better than the observers from Fringe TV Series :)

Burak Hamdi TUFAN.


Tags


Share this Post

Send with Whatsapp

Post a Comment

Success! Your comment sent to post. It will be showed after confirmation.
Error! There was an error sending your comment. Check your inputs!

Comments

  • Thecodeprogram User
    Antonio Jonathan

    Can we use List instead of array to initialize the observer class at first?

    2020/05/25 17:04:13
    • Thecodeprogram User
      Burak Hamdi TUFAN

      Of course you can use a List instead of array. This is just an example and I wanted to show a logic.

      2020/05/26 08:45:23