Object Oriented Programming Patterns for Geeks

The Observer Pattern

 

namespace ooppatterns
{
    using System;
    using System.Collections.Generic;

    internal class Program
    {
        private static void Main( string[] args )
        {
            Server SS = new Server( "Server" );

            Client CC1 = new Client( "Matt", true );

            SS.Connect( CC1 );
            SS.Connect( new Client( "Kelly", true ) );
            SS.Connect( new Client( "Tasha", false ) );
            SS.Connect( new Client( "Moogie", false ) );
            SS.Connect( new Client( "Achies", true ) );
            SS.Connect( new Client( "Marty", false ) );

            SS.Notify( "Restuarant is open.." );

            CC1.NotifyServer( "Want to go for a meal?" );

            SS.Notify( "Restuarant is closed.." );

            CC1.NotifyServer( "Bye!" );
            CC1.Disconnect();

            Console.ReadLine();
        }
    }

    delegate void NotifyHandler( IName sender, string Message );

    interface IName
    {
        string Name { get; }
    }

    // this is the 'subject'
    class Server : IName
    {
        private List<Client> _clients = new List<Client>();
        private NotifyHandler _call;
        private string _name;

        public Server( string name )
        {
            this._name = name;
        }

        public string Name
        {
            get { return this._name; }
        }

        public void Connect( Client client )
        {
            client.Server = this;
            this._call += client.Handle_Notify;
            this._clients.Add( client );
        }

        public void Disconnect( Client client )
        {
            this._call -= client.Handle_Notify;
            Console.WriteLine( "{0}\tHas disconnected!", client.Name );
            client = null;
        }

        // Notify everyone
        public void Notify( string message )
        {
            if ( this._call != null )
                this._call( this, message );
        }

        public void NotifyFromClient( Client sender, string message )
        {
            // Ensure the sender does not get the message it sent out...
            if ( this._call != null )
                foreach ( Delegate blah in this._call.GetInvocationList() )
                    if ( sender.GetHashCode() != blah.Target.GetHashCode() )
                        blah.DynamicInvoke( new object[] { sender, message } );
        }

        public void NotifyFromClientToClient
                     ( Client sender, Client reciever, string message ) { // Ensure only the reciever gets the message sent to it... if ( this._call != null ) foreach ( Delegate blah in this._call.GetInvocationList() ) if ( reciever.GetHashCode() == blah.Target.GetHashCode() ) { blah.DynamicInvoke( new object[] { sender, message } ); break; } } } // This is the 'observer' class Client : IName { private string _name; private bool _wantsFood; private Server _server; public Client( string name, bool wantsfood ) { this._name = name; this._wantsFood = wantsfood; } public Server Server { set { this._server = value; } } public string Name { get { return this._name; } } // Recieve events from server and handle public void Handle_Notify( IName sender, string message ) { Console.WriteLine( "{1} \tnotified {0} \t= {2}",
                              this._name, sender.Name, message ); switch ( message ) { case "Want to go for a meal?": { if ( this._wantsFood ) this.NotifySenderClient( sender, "Sure!" ); else { this.NotifySenderClient( sender, "Nope!" ); this.Disconnect(); } break; } case "Bye!": { this.NotifyServer( "See you later!" ); break; } } } public void Disconnect() { this._server.Disconnect( this ); } // send an event to all other clients public void NotifyServer( string message ) { this._server.NotifyFromClient( this, message ); } // Send an event to a specific client public void NotifySenderClient( IName reciever, string message ) { this._server.NotifyFromClientToClient
                                       ( this, reciever as Client, message ); } } }