Udostępnij za pośrednictwem


Observer Pattern in C# = Events & delegates

One of the most interesting patterns in Design Patterns is the Observer pattern which is listed under Behavioral Patterns, it is really important how to make other classes which are interested in the state of another object get notified when the state changed.

To read more about Observer pattern
This is the classic Observer pattern which used to be good with C++ and Java, however in C# you can implement the same idea using Delegates and Events which is really more concise and elegant way of writing this pattern

 using System;
using System.Collections.Generic;
using System.Text;

namespace Patterns
{
    delegate void StateChangeHandler(State newState);

    enum State
    {
        State1, State2, State3
    }

    class Product
    {
        private State _state;

        public State MyState
        {
            get { return _state; }
            set
            {
                if (_state != value)
                {
                    _state = value;
                    Notify();
                }
            }
        }

        private void Notify()
        {
            if (_onChange != null)
                _onChange(_state);
        }

        private event StateChangeHandler _onChange;

        public event StateChangeHandler OnStateChange
        {
            add
            {
                _onChange += value;
            }
            remove
            {
                _onChange -= value;
            }
        }
    }
}

Take a look on the previous code, the Product class has an important piece of info called _state, and is encapsulated in the property MyState, this class expects that other classes may be interested in observing the changes in the MyState, so the class adds another member which is an Event (_onChange) of type StateChangeHandler delegate, and encapsulated in the Event Property called OnStateChange, and in the setter of the property MyState a small check is made to see whether the new value is different than the older value then the event gets fired.
A typical class which makes use of the Product class will look similar to this

 using System;
using System.Collections.Generic;
using System.Text;

namespace Patterns
{
    class Program
    {
        static void Main(string[] args)
        {
            Product myProduct = new Product();
            myProduct.OnStateChange += new StateChangeHandler(myProduct_OnStateChange);
            myProduct.MyState = State.State3;
        }

        static void myProduct_OnStateChange(State newState)
        {
            Console.WriteLine("State changed to {0}", newState);
        }
    }
}

So now the Program class instantiates an object of type Product and registers itself in the OnStateChange event so whoever changes the MyState property of the object myProduct, the Program class gets notified.
I am not a Design Pattern Guru, however I think this implementation is more suitable for C# and makes use of the unique C# features that produces elegant code.
kick it on DotNetKicks.com

Comments

  • Anonymous
    January 15, 2014
    I like your implementation. What do you think about using an interface defined as Observable. This will be implemented by Product and contain the definitions:  void notify(); and event StateChangeHandler OnStateChange;Sorry about 6 year old comment lol
  • Anonymous
    March 05, 2014
    Nice blog to clear the basic concept of how event use observe pattern.
  • Anonymous
    September 07, 2016
    This is a nice description of this design pattern using events.9 years later, just want to point out a few improvements to make the code leaner:A) Remove the myProduct_OnStateChange() method and use an inline lambda instead, IE:product.OnStateChange += newState => Console.WriteLine("State changed to {0}", newState);B) Remove the Notify() method and simply put its contents in the setter of MyStateC) Use consistent naming conventions for the private backing fields.IE: onStateChange, OnStateChange and _state, State