Saturday, May 12, 2012

C# Abstract Factory Pattern combined with Dependancy Injection andInversion of Control

Saturday, May 12, 2012 Posted by Andre Broers , , , , , ,
In this example I will show the usage of the abstract factory pattern. After this I will show how you can inject the concrete factory dependancy in the sollution. In the final example I will use an Inversion of Control container to get the concrete factory. What I want to demo is that although we will use Inversion of Control we will only use it for the factory. The factory stays responsible for the instanciation and configuration of the IPerson concrete object (an Employee or a Customer). Let's continue.

Abstract Factory Pattern

First the UML Class Diagram of the Abstract Factory:
Code example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MySample
{
    public interface IPerson
    {
        string Name { get; set; }
        string Type { get; set; }
    }

    public class Employee : IPerson
    {
        private string _Name;
        public string Name { get { return _Name; } set { _Name = value; } }
        public string Type { get { return "Employee"; } set { } }
    }

    public class Customer : IPerson
    {
        private string _Name;
        public string Name { get { return _Name; } set { _Name = value; } }
        public string Type { get { return "Customer"; } set { } }
    }

    public interface IPersonAbstractFactory
    {
        IPerson GetPerson();
        IPerson GetPerson(string name);
    }

    public class EmployeeFactory : IPersonAbstractFactory
    {
        public IPerson GetPerson()
        {
            return new Employee() { Name = "UnkownEmployee" };
        }

        public IPerson GetPerson(string name)
        {
            return new Employee() { Name = name };
        }
    }

    public class CustomerFactory : IPersonAbstractFactory
    {
        public IPerson GetPerson()
        {
            return new Customer() { Name = "UnkownCustomer" };
        }

        public IPerson GetPerson(string name)
        {
            return new Customer() { Name = name };
        }
    }

    public class MySample
    {
        public IPerson Person1;
        public IPerson Person2;

        public MySample()
        {
            IPersonAbstractFactory EmployeeFactory = new EmployeeFactory();
            Person1 = EmployeeFactory.GetPerson();
            Person2 = EmployeeFactory.GetPerson("Employee2");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MySample m = new MySample();
            Console.WriteLine(m.Person1.Name + " of " + m.Person1.Type);
            Console.WriteLine(m.Person2.Name + " of " + m.Person2.Type);
            Console.ReadLine();
        }
    }
}

When we run this code the result is:
UnkownEmployee of Employee
Employee2 of Employee

When we run this code we have no way to change what objects the factory will create. When we add dependancy injection we can specify which object types we want the abstract factory to create and configure. Especially the configure part is important. By having a factory we can do all sorts of configuration done by the different factory implementations which will be impossible without the factory pattern.
Now it is time to add dependancy injection.

Dependancy Injection


In the following example dependancy injection is added:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MySample
{
    public interface IPerson
    {
        string Name { get; set; }
        string Type { get; set; }
    }

    public class Employee : IPerson
    {
        private string _Name;
        public string Name { get { return _Name; } set { _Name = value; } }
        public string Type { get { return "Employee"; } set { } }
    }

    public class Customer : IPerson
    {
        private string _Name;
        public string Name { get { return _Name; } set { _Name = value; } }
        public string Type { get { return "Customer"; } set { } }
    }

    public interface IPersonAbstractFactory
    {
        IPerson GetPerson();
        IPerson GetPerson(string name);
    }

    public class EmployeeFactory : IPersonAbstractFactory
    {
        public IPerson GetPerson()
        {
            return new Employee() { Name = "UnkownEmployee" };
        }

        public IPerson GetPerson(string name)
        {
            return new Employee() { Name = name };
        }
    }

    public class CustomerFactory : IPersonAbstractFactory
    {
        public IPerson GetPerson()
        {
            return new Customer() { Name = "UnkownCustomer" };
        }

        public IPerson GetPerson(string name)
        {
            return new Customer() { Name = name };
        }
    }

    public class MySample
    {
        private IPersonAbstractFactory _PersonFactory;
        public IPerson Person1;
        public IPerson Person2;

        public MySample(IPersonAbstractFactory personfactory)
        {
            _PersonFactory = personfactory;
            Person1 = _PersonFactory.GetPerson();
            Person2 = _PersonFactory.GetPerson("Person2");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IPersonAbstractFactory CustomerFactory = new CustomerFactory();
            MySample m = new MySample(CustomerFactory);
            Console.WriteLine(m.Person1.Name + " of " + m.Person1.Type);
            Console.WriteLine(m.Person2.Name + " of " + m.Person2.Type);
            Console.ReadLine();
        }
    }
}

Here we can choose what specific factory we want to use. We inject the dependancy into the MySample class.
The output is:
UnkownCustomer of Customer
Person2 of Customer

Now it is time to use an Inversion of Control container to administer the dependancies in one container. I will use TinyIOC, but there are many IOC libraries in nuget. Use the following to install TinyIOC in your project:
PM> install-package tinyioc
Successfully installed 'TinyIoC 1.1.1'.
Successfully added 'TinyIoC 1.1.1' to MySample.

PM>

Now the example code with Inversion of Control implemented:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TinyIoC;

namespace MySample
{
    public interface IPerson
    {
        string Name { get; set; }
        string Type { get; set; }
    }

    public class Employee : IPerson
    {
        private string _Name;
        public string Name { get { return _Name; } set { _Name = value; } }
        public string Type { get { return "Employee"; } set { } }
    }

    public class Customer : IPerson
    {
        private string _Name;
        public string Name { get { return _Name; } set { _Name = value; } }
        public string Type { get { return "Customer"; } set { } }
    }

    public interface IPersonAbstractFactory
    {
        IPerson GetPerson();
        IPerson GetPerson(string name);
    }

    public class EmployeeFactory : IPersonAbstractFactory
    {
        public IPerson GetPerson()
        {
            return new Employee() { Name = "UnkownEmployee" };
        }

        public IPerson GetPerson(string name)
        {
            return new Employee() { Name = name };
        }
    }

    public class CustomerFactory : IPersonAbstractFactory
    {
        public IPerson GetPerson()
        {
            return new Customer() { Name = "UnkownCustomer" };
        }

        public IPerson GetPerson(string name)
        {
            return new Customer() { Name = name };
        }
    }

    public class MySample
    {
        private IPersonAbstractFactory _PersonFactory;
        public IPerson Person1;
        public IPerson Person2;

        public MySample(IPersonAbstractFactory personfactory)
        {
            _PersonFactory = personfactory;
            Person1 = _PersonFactory.GetPerson();
            Person2 = _PersonFactory.GetPerson("Person2");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var container = TinyIoCContainer.Current;
            container.Register<IPersonAbstractFactory>(new CustomerFactory());

            MySample m = container.Resolve<MySample>();
            Console.WriteLine(m.Person1.Name + " of " + m.Person1.Type);
            Console.WriteLine(m.Person2.Name + " of " + m.Person2.Type);
            Console.ReadLine();
        }
    }
}

Which results in the same output as the previous example. Now we can register all dependancies in a single container. But remember we will not register implementations of the IPerson object.