garyshort.org


I am a Technical Evangelist for Developer Express, my work blog is here but this one is more fun. :-)

February 2008 Entries

The Exams are Finished!

PC270186My eldest, Gemma, is in her final year at school. The prelim exams have just finished and her year have organised a Ceilidh to celebrate. Here's a picture of Gemma before she left; quite the young lady. Apparently she'll be 17 soon; jeez, where'd those years go?

Developer Day Ireland Registration Open

Developer Developer Developer Day Ireland (AKA Techprechaun I) is open for business! I'll be there giving my patterns talk, check out the agenda for more details.

Developer Day Scotland - Voting Open!

Just to let you know, voting for Developer Day Scotland has now opened. If you are coming along and you'd like to see one of sessions I'm doing then you can vote for it using the badge on the sidebar.

Technorati tags:

Double Dispatch Pattern

Let's say you are designing a system and you have worked out what classes you are going to need; but you also realise that as time goes on you are going to have to release other "collaborator" objects for your system. You would like to release these new objects only, and not all the objects in the system, but how are you going to allow existing objects to handle these new "collaborator" objects, when you have no idea what these new objects will do at the time that you are designing the original objects? Yeah its a bummer isn't it?

Well, luckily there is a pattern to deal with this situation, it's called Double Dispatch. In this pattern the original object does not handle messages from its collaborating objects; instead it dispatches the message back to the collaborator along with a reference to itself. The "double dispatching" of a message allows collaborating objects to be added to a system without affecting the original objects.

Below is an example showing an Account object that has to handle a number of Transaction objects. To allow other Transaction objects to be added to the system, as and when required, without affecting the original Account object; the Account object uses "double dispatch" to dispatch the message back to the Transaction object for processing. Clever eh? :-)

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

namespace DoubleDispatch
{
    /// <summary>
    /// I am an abstract class from which all transactions derive
    /// </summary>
    public abstract class Transaction
    {
        //GS - Ensure each derived class implements this method
        public abstract void ExecuteWithAccount(Account theAccount);
    }

    /// <summary>
    /// I represent a bank account
    /// </summary>
    public class Account
    {
        public double Balance { get; set; }

        public void ExecuteTransaction(Transaction theTransaction)
        {
            //GS - I have no knowledge of how this transaction
            //works, so dispatch the message back to the caller
            theTransaction.ExecuteWithAccount(this);
        }
    }

    /// <summary>
    /// I am a debit transaction, I debit an account
    /// balance by my value.
    /// </summary>
    public class DebitTransaction : Transaction
    {
        public double Value { get; set; }

        /// <summary>
        /// GS - Handle the double dispatched message
        /// </summary>
        /// <param name="anAccount"></param>
        public override void ExecuteWithAccount(Account anAccount)
        {
            //GS - Show the user the message has been
            //double dispatched
            Console.WriteLine(
                "Message dispatched back to Debit Transaction.");

            anAccount.Balance -= Value;
        }
    }

    /// <summary>
    /// I am a credit transaction, I credit an account
    /// balance by my value.
    /// </summary>
    public class CreditTransaction : Transaction
    {
        public double Value { get; set; }

        /// <summary>
        /// GS - Handle the double dispatched message
        /// </summary>
        /// <param name="anAccount"></param>
        public override void ExecuteWithAccount(Account anAccount)
        {
            //GS - Show the user the message has been
            //double dispatched
            Console.WriteLine(
                "Message dispatched back to Credit Transaction.");

            anAccount.Balance += Value;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            //GS - Let's test the pattern

            //GS - Create an account and give it an opening balance
            Account theAccount = new Account();
            theAccount.Balance = 100.00;

            //GS - Show the opening balance
            Console.WriteLine("The opening balance is {0}",
                theAccount.Balance);

            //GS - Create a credit transaction for 50 pounds
            CreditTransaction cr = new CreditTransaction();
            cr.Value = 50.00;

            //GS - Apply the transaction to the account
            Console.WriteLine("Account executing the transaction.");
            theAccount.ExecuteTransaction(cr);

            //GS - Show the new balance
            Console.WriteLine("The new balance is {0}",
                theAccount.Balance);

            //GS - Create a debit transaction for 50 pounds
            DebitTransaction dr = new DebitTransaction();
            dr.Value = 50;

            //GS - Apply the transaction
            Console.WriteLine("Account executing the transaction.");
            theAccount.ExecuteTransaction(dr);

            //GS - Show the new balance
            Console.WriteLine("The new balance is {0}",
                theAccount.Balance);

            //GS - Hang around so the user can see the console
            Console.ReadLine();
        }
    }
}

Inversion of Control not DI

A couple of days ago I posted that, although some developers use the terms Inversion of Control and Dependency Injection as if they are the same thing, they are in fact not the same. I said that Dependency Injection was a "kind of" Inversion of Control, it wasn't the only kind and they are not the same thing. I then went on to give an explanation of the Dependency Injection pattern.

Well it turns out that all the developers who thought they were the same thing all read my blog (hey, who knew?) and most of them felt the need to email me telling me I was wrong and challenging me to give an example of Inversion of Control that was not Dependency Injection.

Well okay, fair enough. The other kind of Inversion of Control is based on program control flow and to cut a long story short, it is basically the event based programming model. Here's an example.

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

namespace IOC2
{
    class Program
    {
        static void Main(string[] args)
        {
            //GS - Get the User's name
            Console.WriteLine("Please enter your name:");
            string input = Console.ReadLine();

            //GS - Say hello
            Console.WriteLine("Hello " + input);

            //GS - Wait so the user can see what was written
            //to the console
            Console.ReadLine();
        }
    }
}

 

In the above example the control flow of the program is very simple. A user is asked to input their name and then the program prints out a personalised greeting on the console. Now in Inversion of Control, in relation to control of flow; instead of the programmer specifying a series of events to happen they would register desired responses to particular events and then let some external entity (the user perhaps) take control of the order of these events. In other words, the programmer implements an event driven programming model, as in the following example.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace IOC3
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnGreeting_Click(object sender, EventArgs e)
        {
            //GS - Say hello
            MessageBox.Show("Hello " + txtUserName.Text);
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            //GS - Close the window
            Close();
        }
    }
}

In the example above, you can see that the flow of the program is now not obvious, as it was before. The user may write his name in the textbox, he may change it a bunch of times before pressing the "Greeting" button, or he may not press it at all, but instead press the "Close" button. There is now no way for the programmer to know what the control flow is going to be, the contol flow as "suffered" Inversion of Control.

As you can see, the above is an example of Inversion of Control that does not use Dependency Injection. I stand by what I said in my previous post. Dependency Injection is a "kind of " Inversion of Control, but it's not the only kind, and the two things are not the same.

Inversion of Control Pattern

Okay, in this post we are going to look at Dependency Injection. First thing you have to know (and the reason for the title of this post) is that Inversion of Control is not Dependency Injection. You'll hear developers mix the two terms as if they are the same thing, they're not, Dependency Injection is a "kind of" IoC, but its not the only kind and they are not the same thing.

Right, now we have that out of the way this post is actually about Dependency Injection; so what is DI? Well, normally, when an object has to consume a service, it is that object's responsibility to "know" how to gain access to that service. However, sometimes that is not always desirable; take for example, the instance where you wish to use a different service in test and in production, how will you handle that without code changes? Well, the  answer is the DI pattern.

In the DI pattern the object consuming the service merely provides a property into which the required service is "injected" at runtime. In the example below, you can see that two services are created (each implementing the IService interface) and the required Service (specified in a config file) is "injected" into the Consumer at runtime. Using another service is just a case of changing the value in the config file. Try it out for yourself! :-)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Reflection;

namespace IOC
{
    /// <summary>
    /// GS - I am an intereface that describes a "service"
    /// </summary>
    public interface IService
    {
        void addNumbers(int first, int second);
    }

    /// <summary>
    /// I am the service used for testing
    /// </summary>
    public class TestService : IService
    {
        #region IService Members

        void IService.addNumbers(int first, int second)
        {
            Console.WriteLine("I am the test service");
            int sum = first + second;
            Console.WriteLine("{0} + {1} = {2}",first,second,sum);
        }

        #endregion
    }

    /// <summary>
    /// GS - I am the service used in production
    /// </summary>
    public class ProductionService : IService
    {
        #region IService Members

        void IService.addNumbers(int first, int second)
        {
            Console.WriteLine("I am the production service");
            int sum = first + second;
            Console.WriteLine("{0} + {1} = {2}", first,second,sum);
        }

        #endregion
    }

    /// <summary>
    /// GS - I am the Consumer and I consume the provided Service
    /// </summary>
    public class Consumer
    {
        private int _first;
        private int _second;

        public Consumer(int first, int second)
        {
            _first = first;
            _second = second;
        }

        public IService Service { get; set; }

        public void consumeService()
        {
            if (Service == null)
            {
                throw new Exception("The service has not been set!");
            }

            Console.WriteLine("Consuming service...");
            Service.addNumbers(_first, _second);
        }
    }

    /// <summary>
    /// GS - Let's test the pattern
    /// </summary>
    public class Program
    {
        static void Main(string[] args)
        {
            //GS - Create a consumer
            Consumer aConsumer = new Consumer(3,7);

            //GS - Set the service based on configuration

            //GS - Get the type of the required Service
            Type ServiceType = Type.GetType(
                ConfigurationSettings.AppSettings["ServiceName"]);

            //GS - Get the constructor for this Service
            ConstructorInfo ci =
                ServiceType.GetConstructor(Type.EmptyTypes);

            //GS - Instantiate the Service
            IService theService = ci.Invoke(null) as IService;

            //GS - Inject the Service into the Consumer
            aConsumer.Service = theService;

            //GS - Consume the service
            aConsumer.consumeService();

            //GS - Hang around so the user can see what's
            //written to the console
            Console.Read();
        }
    }
}

Back from my Sick Bed

Sorry it's been so quiet here of late, but I've been off sick (you all better be saying "awww" right now) but I'm back so normal service will be resumed shortly.

Twitter Updates


    Follow me! :-)
    www.flickr.com
    GaryShort's photos More of GaryShort's photos