Star Wars Meets Software Development: A Guide to Implementing the Observer Pattern in C#

Star Wars Meets Software Development: A Guide to Implementing the Observer Pattern in C#

Design Pattern Series

Luke: Master Yoda, I need guidance

Yoda: Yes, young Luke

Luke: "Master Yoda, I am having trouble communicating with the other Jedi in the council. We are all working on different missions, and I do not know what is happening with them."

Yoda: "Ah, young Padawan, you are experiencing a problem with coordination and communication. In programming, this is a common problem that can be addressed with the Observer pattern.

Yoda: For example, we can use this pattern to keep track of the status of Jedi missions. Let's say that you have a JediCouncil class, which contains a list of Jedi Knights who are undertaking different missions. Each of these Jedi Knights has a MissionStatus property that indicates whether the mission is ongoing, completed, or failed.

Yoda: In C#, we can implement the Observer pattern by having the JediCouncil class implement the IObservable interface, and each JediKnight class implement the IObserver interface.

public class JediCouncil : IObservable<JediKnight>
{
    private List<JediKnight> _jediKnights;
    private List<IObserver<JediKnight>> _observers;

    public JediCouncil()
    {
        _jediKnights = new List<JediKnight>();
        _observers = new List<IObserver<JediKnight>>();
    }

    public void AddJediKnight(JediKnight jediKnight)
    {
        _jediKnights.Add(jediKnight);
        NotifyObservers(jediKnight);
    }

    public void RemoveJediKnight(JediKnight jediKnight)
    {
        _jediKnights.Remove(jediKnight);
    }

    public IDisposable Subscribe(IObserver<JediKnight> observer)
    {
        _observers.Add(observer);
        return new Unsubscriber(_observers, observer);
    }

    private void NotifyObservers(JediKnight jediKnight)
    {
        foreach (var observer in _observers)
        {
            observer.OnNext(jediKnight);
        }
    }

    private class Unsubscriber : IDisposable
    {
        private List<IObserver<JediKnight>> _observers;
        private IObserver<JediKnight> _observer;

        public Unsubscriber(List<IObserver<JediKnight>> observers, IObserver<JediKnight> observer)
        {
            _observers = observers;
            _observer = observer;
        }

        public void Dispose()
        {
            if (_observer != null && _observers.Contains(_observer))
            {
                _observers.Remove(_observer);
            }
        }
    }
}
using System;
using System.Collections.Generic;

public class Program
{
    public static void Main(string[] args)
    {
        var jediCouncil = new JediCouncil();
        var Luke = new JediKnight {Name = "Luke Skywalker", Status = MissionStatus.Ongoing};
        var Leia = new JediKnight {Name = "Leia Organa", Status = MissionStatus.Ongoing};
        var Han = new JediKnight {Name = "Han Solo", Status = MissionStatus.Ongoing};

        jediCouncil.AddJediKnight(Luke);
        jediCouncil.AddJediKnight(Leia);
        jediCouncil.AddJediKnight(Han);
        var observer1 = jediCouncil.Subscribe(new JediCouncilObserver());

        //Change the mission status of Luke, triggers the OnNext on the observer
        Luke.Status = MissionStatus.Completed;
        //Change the mission status of Leia, triggers the OnNext on the observer
        Leia.Status = MissionStatus.Failed;

        //Unsubscribe observer1
        observer1.Dispose();

        //Change the mission status of Han, it will not trigger OnNext, observer1 is unsubscribed
        Han.Status = MissionStatus.Completed;
    }
}
public class JediKnight : IObserver<JediKnight>
{
    public string Name { get; set; }
    public MissionStatus Status { get; set; }

    public void OnCompleted()
    {
        // Notify the observer that all updates have been received
    }

    public void OnError(Exception error)
    {
        // Notify the observer of an error
    }

    public void OnNext(JediKnight jediKnight)
    {
        // Update the status of the Jedi Knight
    }
}

Other design pattern articles:

Decorator Pattern: https://zahere.com/yoda-and-the-decorator-pattern-a-lesson-for-luke

Strategy and Factory Pattern: https://zahere.com/opinion-strategy-pattern-factory-pattern-will-be-the-most-used-design-pattern-in-your-career

If you liked my content, do kindly like and share in your network. And don't forget to subscribe to the newsletter to NEVER miss an article.

Did you find this article valuable?

Support Zahiruddin Tavargere by becoming a sponsor. Any amount is appreciated!