Top

Tags


Roadkill .NET Wiki

Google ads

Recommended reading


Search

Saturday
Feb282009

C# Design Patterns: the Observer pattern

Summary

Very similar to the Mediator pattern. The only difference is the 'clients', or the Observers as they are now called, don't broadcast via the mediator (now called the Subject). The observers just sit and listen for event(s) being broadcast by the Subject. The subject can be doing anything it likes completely independent of the Observers; the observers as the name implies just observe, they aren't expected to interact with the subject in the pattern.

Example

System messages is one example of the Observer pattern - where lots of Observers sit listening for various different messages. In Java ActionListeners implement a form of the Observer pattern (and Command pattern), in C# the delegate callback system for events makes the Observer pattern transparent with the syntax of the language. You can find examples of this with events in control libraries.

namespace DesignPatterns
{
    /// <summary>
    /// The use of an interface here mightseem a bit redundent, but it's to keep
    /// inline with the original gang of 4 definition of the pattern. The implementing class
    /// is still responsible for wiring itself to the Subject's notify event.
    /// </summary>
    public interface IObserver
    {
        void Update(string message);
    }

    public class Observer : IObserver
    {
        /// <summary>
        /// A friendly name for the Observer.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// Filters messages starting with the string provided. 
        /// </summary>
        public string MessageFilter { get; set; }

        /// <summary>
        /// Creates a new instance of an Observer.
        /// </summary>
        /// <param name="subject">The class that broadcasts/notifies us of its actions.</param>
        /// <param name="name">A friendly name for the observer.</param>
        public Observer(Subject subject,string name)
        {
            Name = name;
            subject.Notify += new Action<string>(Update);
        }

        /// <summary>
        /// Called each time the Subject notifies this Observer.
        /// </summary>
        /// <param name="message"></param>
        private void Update(string message)
        {
            // Filter the message?
            if (!string.IsNullOrEmpty(MessageFilter))
            {
                if ( message.StartsWith(MessageFilter) )
                    Console.WriteLine("{0} received the message {1}", Name, message);
            }
            else
            {
                Console.WriteLine("{0} received the message {1}", Name, message);
            }
        }
    }

    /// <summary>
    /// This is the class that would perform all or any tasks and then inform
    /// each subscribed Observer when it has down this.
    /// </summary>
    public class Subject
    {
        /// <summary>
        /// Tradionalists might want this to use a delegate called  *EventHandler
        /// but I'm being lazy and using the Generic Action<T> delegate.
        /// </summary>
        public event Action<string> Notify;

        public void Run()
        {
            Thread thread = new Thread(new ThreadStart(InternalRun));
            thread.Start();
        }

        /// <summary>
        /// A small mockup to simulate doing some work.
        /// </summary>
        private void InternalRun()
        {
            string message;

            // 5 basic messages, sleeping between them to simulate
            // intensive IO operations or calculations.
            message = "Calculating Pi to 2000 dp.";
            OnNotify(message);
            Thread.Sleep(2000);

            message = "Copying an item over the network using Vista pre-SP1";
            OnNotify(message);
            Thread.Sleep(2000);

            message = "Finding all files that end in *.dll";
            OnNotify(message);
            Thread.Sleep(2000);

            message = "Formatting a floppy.";
            OnNotify(message);
            Thread.Sleep(2000);

            message = "Spidering google.";
            OnNotify(message);
            Thread.Sleep(2000);
        }

        /// <summary>
        /// Send out a notification to all Observers.
        /// </summary>
        protected virtual void OnNotify(string message)
        {
            if (Notify != null)
                Notify(message);
        }
    }
}

Reader Comments

There are no comments for this journal entry. To create a new comment, use the form below.

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>
« Google chrome about pages | Main | Output from the Uri class »