Tuesday, 25 September 2018

Abstract Factory Pattern

The abstract factory pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. Thus the difference between the "Abstract Factory Pattern" and the "Method Factory Pattern" is that the latter constructs a single object and the former constructs multiple objects that are in some way related.

to illustrate this let's think of Barbie's and GI-Joes, in essence they're both dolls, they both have a head, two  arms, two legs, a torso, and neither have genitals, but they can be thought of as distinct Objects. They can both be made with the same factory just with a slightly different setup;


Now our application has an AbstractFactory, this abstract factory can be one of two things either a GiJoeFactory or a Barbie factory, which create either GiJoes or Barbies. Both the GiJoes and Barbies realize the IDoll interface.

The difference between a Factory pattern and an Abstract Factory Pattern to me is that in the former the application has either a BarbieFactory or a GiJoeFactory where as with the later the application can decide which factory to use. Let's take a look at the code example.

first let's setup our dolls.

interface IDoll
{
    string Name { get; set; }
    string SayHi();
}

class GiJoeIDoll
{
    public string Name { get; set; }
    public string SayHi() => $"\r\nI'm a GiJoe, my name is {Name}";
}

class BarbieIDoll
{
    public string Name { get; set; }
    public string SayHi() => $"\r\nI'm a Barbie, my name is {Name}";
}

no big deal, just an interface with two concrete classes that realize it.

Next let's look at our factories

interface IDollFactory IDoll CreateDoll(); }

class GiJoeFactoryIDollFactory
{
    static Random rnd = new Random(DateTime.Now.Millisecond * DateTime.Now.Second);
    string[] names = new[] { "Joe", "Dan", "Rick", "Jack" };

    public IDoll CreateDoll() => new GiJoe { Name = names[rnd.Next(names.Length)] };
}

class BarbieFactoryIDollFactory
{
    static Random rnd = new Random(DateTime.Now.Millisecond * DateTime.Now.Second);
    string[] names = new[] { "Barbie", "Jessica", "Jenifer", "Nicole" };

    public IDoll CreateDoll() => new Barbie { Name = names[rnd.Next(names.Length)] };
}


now since this is a contrived example there's very little of interest here other than the fact that the private names array varies between the two factories to allow some slight variance within the two factories. next let's look at the application itself.

class Program
{
    static IDollFactory dollFactory = null;

    static void Main(string[] args)
    {
        int selection = -1;
        do
        {
            switch (selection)
            {
                case 1:
                    dollFactory = new BarbieFactory();
                    break;
                case 2:
                    dollFactory = new GiJoeFactory();
                    break;
                default:
                    dollFactory = null;
                    selection = -1;
                    break;
            }

            if (dollFactory != null)
                Console.WriteLine(dollFactory.CreateDoll().SayHi());
            ConsoleDollType();

        } while (int.TryParse(Console.ReadKey().KeyChar.ToString(), out selection) && selection != 0);
    }

    static void ConsoleDollType()
    {
        Console.WriteLine("what type of toy would you like?");
        Console.WriteLine("1) a doll");
        Console.WriteLine("2) an action figure");
        Console.WriteLine("0) exit");
    }
}

now notice that within the switch statement the abstract dollFactory variable is set to a concrete implementation of of the IDollFactory interface. From what i gather this is what makes it an Abstract Factory Pattern and not just a Factory Pattern, the fact that we change our factory implementation based on some sort logic.