Design patterns in C# – part 20 (Observer pattern)

Role

The Observer pattern defines a relationship between objects so that when one changes its state, all the others are notified accordingly.

Design

ObserverPattern

Implementation

  • IObserver -> IStateObserver
  • Observer -> StateObserver
  • Subject -> StatesGenerator
using System;
using System.Collections;
using System.Threading;

namespace ObserverPattern
{
    public class TestObserverPattern
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("---First invoking---\n\n");

            var subject = new StatesGenerator();
            var stateObserverFirst = new StateObserver("First Observer", subject);
            subject.Go();
            subject.Thread.Join();

            Console.WriteLine("\n\n\n\n---Second invoking---\n\n");

            var stateObserverSecond = new StateObserver("Second Observer", subject);
            subject.Go();
            subject.Thread.Join();

            Console.WriteLine("\n\n\n\n---Explicite state changed---\n\n");
            stateObserverFirst.Update("Final State");
            stateObserverSecond.Update("Final State");
        }
    }

    public class StatesGenerator
    {
        #region Delegates

        public delegate void Callback(string message);

        #endregion

        private const int WaitingTime = 500;
        private readonly States _states;

        public StatesGenerator()
        {
            this._states = new States();
        }

        public string SubjectState { get; set; }
        public Thread Thread { get; set; }
        public event Callback Notify;

        public void Go()
        {
            this.Thread = new Thread(this.Run);
            this.Thread.Start();
        }

        private void Run()
        {
            foreach (string s in this._states)
            {
                Console.WriteLine("States Generator: \n\t{0}", s);
                this.SubjectState = s;
                this.Notify(s);
                Thread.Sleep(WaitingTime);
            }
        }

        #region Nested type: States

        private class States : IEnumerable
        {
            private readonly string[] _states = {"State One", "State Two", "State Three"};

            #region IEnumerable Members

            public IEnumerator GetEnumerator()
            {
                foreach (string state in this._states)
                {
                    yield return state;
                }
            }

            #endregion
        }

        #endregion
    }

    public interface IStateObserver
    {
        void Update(string state);
    }

    public class StateObserver : IStateObserver
    {
        private readonly string _name;
        private string _state;

        public StateObserver(string name, StatesGenerator statesGenerator)
        {
            this._name = name;
            statesGenerator.Notify += this.Update;
        }

        #region IStateObserver Members

        public void Update(string subjectState)
        {
            this._state = subjectState;
            Console.WriteLine("{0}: \n\t{1}", this._name, this._state);
        }

        #endregion
    }
}

OUTPUT:

—First invoking—

States Generator:
State One
First Observer:
State One
States Generator:
State Two
First Observer:
State Two
States Generator:
State Three
First Observer:
State Three

—Second invoking—

States Generator:
State One
First Observer:
State One
Second Observer:
State One
States Generator:
State Two
First Observer:
State Two
Second Observer:
State Two
States Generator:
State Three
First Observer:
State Three
Second Observer:
State Three

—Explicite state changed—

First Observer:
Final State
Second Observer:
Final State

Use when

  • There are aspects to an abstraction that can vary independently.
  • Changes in one object need to be propagated to a selection of other objects, not all of them.
  • The object sending the changes does not need to know about the receivers.

Bibliography

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s