Design patterns – Observer

Observer pattern is used when you have a collection of objects (observers) which should monitor the state of the single other object (subject).
All observers should implement IObserver interface with single method (Update()). Subject collects all observers and raises Update() method when it has changed to inform them.

In my example I have RandomNumberGenerator as a subject, it is derived from SubjectBase, where main logic resides.
Generator just draws random numbers from time to time.
This number along with date is SubjectState. The state is publicly available to the observers by GetState() method.
Collection of observers is saved in subject (see Attach() and Detach() methods).
When new number is generated generator notifies observers.

The subject part
a) the interface

    /// <summary>
    /// Iterface to be implemented by a class which watches for changes.
    /// </summary>
    interface IObserver
    {
        /// <summary>
        /// Updates state of the object when subject is changed.
        /// </summary>
        void Update();
    }

b) The base implementation

    /// <summary>
    /// Generic item which performs changes and informs observers about this change.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    abstract class SubjectBase<T>
    {
        protected IList<IObserver> _observers;

        private T _state { get; set; }

        public SubjectBase(T initialState)
        {
            _state = initialState;
            _observers = new List<IObserver>();
        }

        /// <summary>
        /// Adds observer to collection.
        /// </summary>
        /// <param name="observer"></param>
        public void Attach(IObserver observer)
        {
            _observers.Add(observer);
        }

        /// <summary>
        /// Removes observer from collection.
        /// </summary>
        /// <param name="observer"></param>
        public void Detach(IObserver observer)
        {
            _observers.Remove(observer);
        }

        /// <summary>
        /// Notifies collected observers about change.
        /// </summary>
        private void Notify()
        {
            foreach (var o in _observers)
            {
                o.Update();
            }
        }

        /// <summary>
        /// Gets the state of the object. Observers use this method to see what is changed.
        /// </summary>
        /// <returns></returns>
        public T GetState()
        {
            return _state;
        }

        /// <summary>
        /// Sets new state of the subject.
        /// </summary>
        /// <param name="newState"></param>
        public void SetState(T newState)
        {
            if (!_state.Equals(newState))
            {
                _state = newState;
                Notify();
            }
        }
    }

c) The concrete implmentation

    class RandomNumberGenerator : SubjectBase<NumberInfo>
    {
        public RandomNumberGenerator(NumberInfo initialState) : base(initialState)
        {
            Task.Run(() =>
            {
                while (true)
                {
                    var randomNumber = new Random().Next();
                    var state = new NumberInfo(randomNumber);
                    this.SetState(state);
                    Thread.Sleep(3000);
                }
            });
        }
    }

d) The subject state

    class SubjectState
    {
        public int MagicNumber { get; set; }
        public DateTime LastChange { get; set; }
    }

The observers part
Observers implment IObserver interface and are called RandomNumberObservers. Always when subject changes, the Update() method is called and observer can process something.
a) The interface

    /// <summary>
    /// Iterface to be implemented by a class which watches for changes.
    /// </summary>
    interface IObserver
    {
        /// <summary>
        /// Updates state of the object when subject is changed.
        /// </summary>
        void Update();
    }

b) The concrete implementation

    class RandomNumberObserver : IObserver
    {
        private string _name;
        private RandomNumberGenerator _subject;

        public RandomNumberObserver(string name, RandomNumberGenerator subject)
        {
            _name = name;
            _subject = subject;
        }

        public void Update()
        {
            PrintYourself();
        }

        private void PrintYourself()
        {
            var state = _subject.GetState();
            Console.WriteLine($"I'm {_name} and current number set at {state.Timestamp.ToLongTimeString()} is {state.Number}.");
        }
    }

And finally this is how it can be used. Subject and observers are created. After that you attach observers to the subject. When subject is changed, observers respond to that change.

        /// <summary>
        /// Presents observer pattern.
        /// Number generator is the subject. Every few seconds changes the random number and informs about the change. 
        /// Two observers print the current random number when they are informed about the change.
        /// </summary>
        private static void ObserverTest()
        {
            var initialState = new NumberInfo(0);
            var subject = new RandomNumberGenerator(initialState);
            var observerA = new RandomNumberObserver("ObserverA", subject);
            subject.Attach(observerA);
            var observerB = new RandomNumberObserver("ObserverB", subject);
            subject.Attach(observerB);
        }
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