Pragmatic Developer

Ali Özgür

Bookmark Blog

Add to Technorati Favorites

Google Talk

Chat with Ali Özgür

Purchase PragmaSQL from

Calendar

«  December 2008  »
MoTuWeThFrSaSu
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234
View posts in large calendar

Tag Cloud

Don't show

    Authors

    Recent Comments

    Banners




    GoF book says that "Observer pattern should defina a one-to-many dependency between objects so that when one object changes state, all its dependenst are notified and updated automatically". Subscribing to RSS feeds is a nice analogy.  You subscribe to RSS feeds to show interest and you become an observer who demand for notification and RSS feeds become the subject and are responsable for providing information to all subscribers. I think this bit of information describing the pattern is enough, now lets see how we implement observer pattern.

    Lets assume that we are developing a car controller software. One of the requirements is "Provide visual warning to the driver if seat belts are not locked". To meet the requirement we design

    • SeatBelt class which is the subject. This class should notify interested objects about the state changes
    • SeatBeltMonitor class is our observer. This class monitors for status change messages provided by the SeatBelt and displays messages

    Implementing Observer Pattern in conventional way 

    Download GoF_Patterns_Observer1.rar (20,36 kb)

    It is suggested to specify an interface or abstract classes when dealing with patterns so that the objects we create will adhere to some predefined contract. So we start our implementation by specifying two interfaces ISubject and IObserver

    001    public interface ISubject
    002    {
    003        void RegisterObserver(IObserver observer);
    004        void RemoveObserver(IObserver observer);
    005    }
    006
    007    public interface IObserver
    008    {
    009        void Update(bool locked);
    010    }

    As I've mentioned above our SeatBelt class is the subject (source) of the state change and should implement the contract so that interested parties shall define their interest to the state changes or stop receiving state change notification. Here is our SeatBelt code

    001    public class SeatBelt:ISubject
    002    {
    003        private IList<IObserver> _observers = new List<IObserver>();
    004
    005        private bool _locked = false;
    006        public bool Locked
    007        { 
    008            get { return _locked; }
    009            set { _locked = value; UpdateObservers(); } 
    010        }
    011
    012        
    013        private void UpdateObservers()
    014        {
    015            foreach (IObserver observer in _observers)
    016            {
    017                try
    018                {
    019                    observer.Update(_locked);
    020                }
    021                catch (Exception ex)
    022                {
    023                    Console.WriteLine("Can not update observer. Error:" + ex.Message);
    024                }
    025            }
    026        }
    027
    028        #region IObserver Members
    029
    030        public void RegisterObserver(IObserver observer)
    031        {
    032            if (observer == null || _observers.Contains(observer))
    033                return;
    034
    035            _observers.Add(observer);
    036        }
    037
    038        public void RemoveObserver(IObserver observer)
    039        {
    040            if (observer == null || !_observers.Contains(observer))
    041                return;
    042
    043            _observers.Remove(observer);
    044        }
    045
    046        #endregion
    047    }
     

    When value of the Locked property changes all registered observers will be notified. Our SeatBeltMonitor class simply responds to the change with a message. Here is our observer code

    001    public class SeatBeltMonitor:IObserver
    002    {
    003        #region IObserver Members
    004
    005        public void Update(bool locked)
    006        {
    007            if (!locked)
    008                Console.WriteLine("Please lock your seat belt!");
    009            else
    010                Console.WriteLine("Seat belt OK.");
    011        }
    012        #endregion
    013    }

    001    static void Main(string[] args)
    002        {
    003            SeatBelt seatBelt = new SeatBelt();
    004            SeatBeltMonitor monitor = new SeatBeltMonitor();
    005
    006            seatBelt.RegisterObserver(monitor);
    007            // Prints OK.
    008            seatBelt.Locked = true;
    009            
    010            //Prints warning
    011            seatBelt.Locked = false;
    012
    013            seatBelt.RemoveObserver(monitor);
    014            // Nothing will be printed
    015            seatBelt.Locked = true;
    016
    017
    018            Console.Read();
    019        }

     

    Implementing Observer Pattern with .NET Events

    Download GoF_Patterns_Observer2.rar (20,72 kb)

    .NET and C# provides a very flexible implementation of Observer Pattern through events and delegates.Here is the code for the alternative implementation. Some differences are

    • We do not need to define contracts through ISubject and IObserver interfaces
    • We specify the contract through delegate definitions (SeatBeltStatusChangedDelegate)
    • We use custom classes as convention to pass status data from subject to the observers (SeatBeltEventArgs  class)
    • We register method pointers through events of the subject rather than registering our observer objects to our subject. In this case method signature is used as contract
    • We use overloaded + and - operators for registration

    001    public class SeatBeltEventArgs : EventArgs
    002    {
    003        public bool Locked { get; set; }
    004    }
    005
    006    public class SeatBelt
    007    {
    008        private bool _locked = false;
    009        public bool Locked
    010        {
    011            get { return _locked; }
    012            set { _locked = value; FireStatusChangeEvent(); }
    013        }
    014
    015        private SeatBeltStatusChangedDelegate _statusChanged;
    016        public event SeatBeltStatusChangedDelegate StatusChanged
    017        {
    018            add { _statusChanged += value; }
    019            remove { _statusChanged -= value; }
    020        }
    021
    022
    023        private void FireStatusChangeEvent()
    024        {
    025            if (_statusChanged == null)
    026                return;
    027
    028            Delegate[] invokeList = _statusChanged.GetInvocationList();
    029            foreach (SeatBeltStatusChangedDelegate d in invokeList)
    030            {
    031                SeatBeltEventArgs args = new SeatBeltEventArgs();
    032                args.Locked = _locked;
    033                try
    034                {
    035                    d.Invoke(this, args);
    036                }
    037                catch (Exception ex)
    038                {
    039                    Console.WriteLine("Can not update observer. Error:" + ex.Message);
    040                }
    041            }
    042        }
    043    }
    044
    045    public delegate void SeatBeltStatusChangedDelegate(object sender, SeatBeltEventArgs args);
    046
    047
    048

    001    public class SeatBeltMonitor
    002    {
    003        public void RespondToSeatBeltStatusChange( object sender, SeatBeltEventArgs args)
    004        {
    005            if (!args.Locked)
    006                Console.WriteLine("Please lock your seat belt!");
    007            else
    008                Console.WriteLine("Seat belt OK.");
    009        }
    010    }
     

    001    static void Main(string[] args)
    002        {
    003            SeatBelt seatBelt = new SeatBelt();
    004            SeatBeltMonitor monitor = new SeatBeltMonitor();
    005
    006            seatBelt.StatusChanged += new SeatBeltStatusChangedDelegate(monitor.RespondToSeatBeltStatusChange);
    007            // Prints OK.
    008            seatBelt.Locked = true;
    009
    010            //Prints warning
    011            seatBelt.Locked = false;
    012
    013            seatBelt.StatusChanged -= new SeatBeltStatusChangedDelegate(monitor.RespondToSeatBeltStatusChange);
    014            // Nothing will be printed
    015            seatBelt.Locked = true;
    016
    017
    018            Console.Read();
    019        }
    020
    021
    022
     


    Posted in: C# , GoF Patterns  Tags:

    Currently rated 4.0 by 1 people

    • Currently 4/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5

    Comments


    October 3. 2008 15:53
    pingback
    Pingback from sehajpal.com

    Ashish Sehajpal

    http://www.sehajpal.com/blog/?p=91


    November 20. 2008 08:23
    Busby SEO Test
    thanks for the codes it really helps me!!

    http://pinayspeak.com/pinaytest/

    Add comment


    (Will show your Gravatar icon)  

      Country flag

    [b][/b] - [i][/i] - [u][/u]- [quote][/quote]



    Live preview


     
    December 5. 2008 04:42

    no site