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.

Thursday, 13 September 2018

Factory Method Pattern

In a previous post I mentioned the "Simple Factory Pattern" which in essence is the same thing as  the "Factory Method Pattern" with the only real difference being the fact that in this case the factory adheres to an abstraction. Before we get into the factory let's take a look at our data model.

interface IShape
{
    double[] Args { get; set; }
    double GetArea();
    double GetPerimeter();
    void Print();
}

class SquareIShape
{
    public double[] Args { get; set; }
    public Square(double s) => Args = new double[] { s };

    public double GetArea() => Math.Pow(Args[0], 2);
    public double GetPerimeter() => Args[0] * 4;

    public void Print()
    {
        Console.Write($"I am a {this.GetType().Name}");
        Console.WriteLine($"Area:{GetArea()}\tPerimeter:{GetPerimeter()}\r\n");
    }
}

class RectangleIShape
{
    public double[] Args { get; set; }
    public Rectangle(double width, double height) => Args = new double[] { width, height };

    public double GetArea() => Args[0] * Args[1];
    public double GetPerimeter() => Args[0] * 2 +  Args[1] * 2;
    public void Print()
    {
        Console.WriteLine($"I am a {this.GetType().Name}");
        Console.WriteLine($"Area:{GetArea()}\tPerimeter:{GetPerimeter()}\r\n");
    }
}

class TriangleIShape
{
    public double[] Args { get; set; }
    public Triangle(double adjacent, double theta, double hypotenuse)
        => Args = new double[] { adjacent, theta, hypotenuse };

    public double GetArea()
    {
        var adjacent = Args[0];
        var theta = ToRadians(Args[1]);
        var hypotenuse = Args[2];
        var height = Math.Sin(theta) * hypotenuse;

        return adjacent * height / 2;

    }
    public double GetPerimeter()
    {
        var adjacent = Args[0];
        var theta = ToRadians(Args[1]);
        var hypotenuse = Args[2];
        var height = Math.Sin(theta) * hypotenuse;

        var alpha = ToRadians(180 - 90 - Args[1]);
        var subBase = Math.Sin(alpha) * hypotenuse;
        var diffBase = adjacent - subBase;

        var opposite = Math.Sqrt(Math.Pow(height, 2) + Math.Pow(diffBase, 2));

        return adjacent + hypotenuse + opposite;

    }
}

Now we have a base shape interface that defines a couple of functions and a storage mechanism for our shape values let's make notice that all of our implementations of the IShape interface leverage a different constructor. Thus if we wanted to create instances of our shapes from a dataset we'd have something like the following.

class Program
{
    static void Main(string[] args)
    {
        var data = new[,] { { new[] { 6.0 } }, { new[] { 3.0, 4.0 } }, { new[] { 5.0, 30.0, 7.0 } }, { new[] { 5.0, 3.0 } } };

        foreach (var d in data)
            if (d.Length == 1)
                (new Square(d[0])).Print();
            else if (d.Length == 2)
                (new Rectangle(d[0], d[1])).Print();
            else if (d.Length == 3)
                (new Triangle(d[0], d[1], d[2])).Print();
    }

}

For each data entry we have to check how many values it contains and then create a shape appropriately, now that's sloppy even in this contrived example, so let's define a factory to handle the creation of our shapes.

from our UML you can see that all of our shapes implement the IShape interface, then we have an interface that describes our factory, it defines one function that returns instances of our shapes then that interface is realized by our ShapeFactory which encapsulates our instantiation logic.

interface IShapeFactory
{
    IShape CreateShape(double[] args);
}

Simple as that just one function that takes in our data and returns an instance of IShape; next let's create a concrete implementation of our factory

class ShapeFactoryIShapeFactory
{
    public IShape CreateShape(double[] args)
    {
        if (args.Length == 1)
            return new Square(args[0]);

        if (args.Length == 2)
            return new Rectangle(args[0], args[1]);

        if (args.Length == 3)
            return new Triangle(args[0], args[1], args[2]);

        return null;
    }
}

now we've encapsulated our instantiation logic into a factory and now let's use our factory in our program

class Program
{
    static void Main(string[] args)
    {
        var data = new[,] {
            { new[] { 6.0 } }, { new[] { 3.0, 4.0 } },
            { new[] { 5.0, 30.0, 7.0 } }, { new[] { 5.0, 3.0 } }
        };

        var shapeFactory = new ShapeFactory();
        foreach (var d in data)
            shapeFactory.CreateShape(d).Print();
    }
}

and voila much cleaner code, now that our factory handles the instantiation of our shapes.