Ali Özgür - The Pragmatic Developer

My Amazon.com Wish List

RecentComments

Comment RSS

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    {
004
005        void RegisterObserver(IObserver observer);
006
007        void RemoveObserver(IObserver observer);
008
009    }
010
011
012
013    public interface IObserver
014
015    {
016
017        void Update(bool locked);
018
019    }

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    {
004
005        private IList<IObserver> _observers = new List<IObserver>();
006
007
008
009        private bool _locked = false;
010
011        public bool Locked
012
013        { 
014
015            get { return _locked; }
016
017            set { _locked = value; UpdateObservers(); } 
018
019        }
020
021
022
023        
024
025        private void UpdateObservers()
026
027        {
028
029            foreach (IObserver observer in _observers)
030
031            {
032
033                try
034
035                {
036
037                    observer.Update(_locked);
038
039                }
040
041                catch (Exception ex)
042
043                {
044
045                    Console.WriteLine("Can not update observer. Error:" + ex.Message);
046
047                }
048
049            }
050
051        }
052
053
054
055        #region IObserver Members
056
057
058
059        public void RegisterObserver(IObserver observer)
060
061        {
062
063            if (observer == null || _observers.Contains(observer))
064
065                return;
066
067
068
069            _observers.Add(observer);
070
071        }
072
073
074
075        public void RemoveObserver(IObserver observer)
076
077        {
078
079            if (observer == null || !_observers.Contains(observer))
080
081                return;
082
083
084
085            _observers.Remove(observer);
086
087        }
088
089
090
091        #endregion
092
093    }
 

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    {
004
005        #region IObserver Members
006
007
008
009        public void Update(bool locked)
010
011        {
012
013            if (!locked)
014
015                Console.WriteLine("Please lock your seat belt!");
016
017            else
018
019                Console.WriteLine("Seat belt OK.");
020
021        }
022
023        #endregion
024
025    }

001    static void Main(string[] args)
002
003        {
004
005            SeatBelt seatBelt = new SeatBelt();
006
007            SeatBeltMonitor monitor = new SeatBeltMonitor();
008
009
010
011            seatBelt.RegisterObserver(monitor);
012
013            // Prints OK.
014
015            seatBelt.Locked = true;
016
017            
018
019            //Prints warning
020
021            seatBelt.Locked = false;
022
023
024
025            seatBelt.RemoveObserver(monitor);
026
027            // Nothing will be printed
028
029            seatBelt.Locked = true;
030
031
032
033
034
035            Console.Read();
036
037        }

 

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    {
004
005        public bool Locked { get; set; }
006
007    }
008
009
010
011    public class SeatBelt
012
013    {
014
015        private bool _locked = false;
016
017        public bool Locked
018
019        {
020
021            get { return _locked; }
022
023            set { _locked = value; FireStatusChangeEvent(); }
024
025        }
026
027
028
029        private SeatBeltStatusChangedDelegate _statusChanged;
030
031        public event SeatBeltStatusChangedDelegate StatusChanged
032
033        {
034
035            add { _statusChanged += value; }
036
037            remove { _statusChanged -= value; }
038
039        }
040
041
042
043
044
045        private void FireStatusChangeEvent()
046
047        {
048
049            if (_statusChanged == null)
050
051                return;
052
053
054
055            Delegate[] invokeList = _statusChanged.GetInvocationList();
056
057            foreach (SeatBeltStatusChangedDelegate d in invokeList)
058
059            {
060
061                SeatBeltEventArgs args = new SeatBeltEventArgs();
062
063                args.Locked = _locked;
064
065                try
066
067                {
068
069                    d.Invoke(this, args);
070
071                }
072
073                catch (Exception ex)
074
075                {
076
077                    Console.WriteLine("Can not update observer. Error:" + ex.Message);
078
079                }
080
081            }
082
083        }
084
085    }
086
087
088
089    public delegate void SeatBeltStatusChangedDelegate(object sender, SeatBeltEventArgs args);
090
091
092

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

001    static void Main(string[] args)
002
003        {
004
005            SeatBelt seatBelt = new SeatBelt();
006
007            SeatBeltMonitor monitor = new SeatBeltMonitor();
008
009
010
011            seatBelt.StatusChanged += new SeatBeltStatusChangedDelegate(monitor.RespondToSeatBeltStatusChange);
012
013            // Prints OK.
014
015            seatBelt.Locked = true;
016
017
018
019            //Prints warning
020
021            seatBelt.Locked = false;
022
023
024
025            seatBelt.StatusChanged -= new SeatBeltStatusChangedDelegate(monitor.RespondToSeatBeltStatusChange);
026
027            // Nothing will be printed
028
029            seatBelt.Locked = true;
030
031
032
033
034
035            Console.Read();
036
037        }
038
039
040
 


Posted in: C# , GoF Patterns  Tags:

Comments


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

Ashish Sehajpal

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


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

   http://pinayspeak.com/pinaytest/


December 9. 2008 09:50
Busby SEO Test
great tips and code, thanks for sharing this

   http://www.baliinc.net/


December 16. 2008 04:31
busby seo test
I'm late for this tips.

   http://intersindo.com/seo-contest/


January 10. 2009 02:50
gosip artis terbaru
thank you for the .net code. It's been a lifesaver Smile

   http://oktavita.com/


March 27. 2009 16:52
luxury villas seminyak
thanks for this great post and thanks for sharing this information.

   http://seminyak-villa.com/seminyak-luxury-villas/

Comments are closed