Skip to main content

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

Design Pattern Series

Published 3 min readMarkdown
Part of seriesSoftware Development and System Design
Star Wars Meets Software Development: A Guide to Implementing the Observer Pattern in C#

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.

About the author

  • I am a Journalist-turned-Software Engineer. I love coding and the associated grind of learning every day. A firm believer in social learning, I owe my dev career to all the tech content creators I have learned from. This is my contribution back to the community.

No comments yet. Be the first to comment.

More from this blog