Abstract Factories, shaken not stirred.

The abstract factory is one of the Gang of Four creational patterns and as the name implies it is concerned with the abstraction of creating. The factory part of this pattern can be very useful if an object is created in many places throughout your code. It helps you to centralise its initialisation giving you a nice separation of concerns, the code that consumes the object is insulated from the code that creates the object. On the other hand the abstract part is just as useful, the factory returns a contract rather than a concrete type. The consumer of the factory only knows about the contract and there for you can swap in and out implementations (even at runtime) with little effort.

It has been pointed out to me in the past that you do have to be careful when using this pattern, and I agree with this reservation. It can be pointless work if the usage scope of the object is small, a private class is a good example of possible overuse of an abstract factory.

I have created an example project where a bar person makes a person’s favourite drinks.

There are three people:

Mr Bond Loves a Shaken Martini

namespace Patterns.AbstractFactory.People
{
    using Patterns.AbstractFactory.Drinks;

    /// <summary>
    /// The mr bond.
    /// </summary>
    public class MrBond : ICocktailFactory
    {
        /// <summary>
        /// The favorite drink.
        /// </summary>
        /// <returns>
        /// The <see cref="IDrink"/>.
        /// </returns>
        public IDrink FavoriteDrink()
        {
            return new ShakenMartini();
        }
    }
}

Scott Loves a Coffee Martini

namespace Patterns.AbstractFactory.People
{
    using Patterns.AbstractFactory.Drinks;

    /// <summary>
    /// The scott.
    /// </summary>
    public class Scott : ICocktailFactory
    {
        /// <summary>
        /// The favorite drink.
        /// </summary>
        /// <returns>
        /// The <see cref="IDrink"/>.
        /// </returns>
        public IDrink FavoriteDrink()
        {
            return new CoffeeMartini();
        }
    }
}

I love a Stirred Martini

namespace Patterns.AbstractFactory.People
{
    using Patterns.AbstractFactory.Drinks;

    /// <summary>
    /// The aaron.
    /// </summary>
    public class Aaron : ICocktailFactory
    {
        /// <summary>
        /// The favorite drink.
        /// </summary>
        /// <returns>
        /// The <see cref="IDrink"/>.
        /// </returns>
        public IDrink FavoriteDrink()
        {
            return new StirredMartini();
        }
    }
}

Scott, Mr Bond, and myself are the factories and the bar person is the client who uses those factories.

namespace Patterns.AbstractFactory
{
    using Patterns.AbstractFactory.Drinks;
    using Patterns.AbstractFactory.People;

    /// <summary>
    /// The bar person.
    /// </summary>
    public class BarPerson : IBarPerson 
    {
        /// <summary>
        /// The mix drink.
        /// </summary>
        /// <typeparam name="T">
        /// The factory that supplies the drink to me made.
        /// </typeparam>
        /// <returns>
        /// The <see cref="IDrink"/>.
        /// </returns>
        public IDrink MixDrink<T>() where T : ICocktailFactory, new()
        {
            return new T().FavoriteDrink();
        }
    }
    ```

The BarPerson asks what the factories favourite drink is, and the factory returns an instance of that IDrink. There are unit tests included to verify that the correct drink was returned by the BarPerson.

namespace Patterns.AbstractFactory
{
    using NUnit.Framework;

    using Patterns.AbstractFactory.Drinks;
    using Patterns.AbstractFactory.People;

    [TestFixture]
    public class BarPersonTests
    {
        [Test]
        public void CanCreateShakenMartiniForMrBond()
        {
            var barPerson = new BarPerson();
            var drink = barPerson.MixDrink<MrBond>();

            Assert.That(drink, Is.TypeOf<ShakenMartini>());
        }

        [Test]
        public void CanCreateStirredMartiniForAaron()
        {
            var barPerson = new BarPerson();
            var drink = barPerson.MixDrink<Aaron>();

            Assert.That(drink, Is.TypeOf<StirredMartini>());
        }

        [Test]
        public void CanCreateCoffeeMartiniForScott()
        {
            var barPerson = new BarPerson();
            var drink = barPerson.MixDrink<Scott>();

            Assert.That(drink, Is.TypeOf<CoffeeMartini>());
        }
    }
}