Friday, 10 November 2017

Compostie Pattern

The composite pattern in simplest terms allows you to group nodes within a tree structure and treat them as one node, in other words it lets you treat a group of things as if they where just one thing. so let's take a look at what that means. To get started let's create an IWidget interface.

interface IWidget
{
    string Name { get; set; }
    int Weight { get; }
}

now this interface simply defines two properties, one is an identifier and the other is the weight of our widget, next let's create some concrete implementations of our interface, namely screw and bolt. we're going to pretend that we are a part supplier.

class Screw : IWidget
{
    public string Name { get; set; }
    public int Weight { get; } = 250;
    public Screw(string name) => Name = name;
}

class Bolt : IWidget
{
    public string Name { get; set; }
    public int Weight { get; } = 100;
    public Bolt(string name) => Name = name;
}

simple enough; now here's where it starts to get interesting, let's create a dunnage class. A dunnage is just going to be a box of widgets, but we are going to implement the IWidget interface on our dunnage class.

class Dunnage : IWidget
{
    public IEnumerable<IWidget> Widgets { get; set; }

    public string Name { get; set; }

    public int Weight
    {
        get
        {
            int total = 0;
            foreach (var w in Widgets)
                total += w.Weight;
            return total;
        }
    }
}

now as you see for our dunnage class our weight property iterates over all of the widgets in the dunnage and outputs their total weight.

now in our main we can lump our individual widgets in with the Dunnage in one shipment collection.

class Program
{
    static void Main(string[] args)
    {
        IWidget widget0 = new Screw("foo");
        IWidget widget1 = new Bolt("bar");

        IWidget dunnage1 = new Dunnage {
            Name = "Bin A",
            Widgets = new IWidget[] { new Screw("bill"), new Screw("foo"), new Bolt("bar")}};

        var shipment = new List<IWidget>(new IWidget[] { widget0, widget1, dunnage1 });
        var totalWeight = shipment.Select(w=> w.Weight).Aggregate((x, y) => x += y);

        Console.WriteLine(totalWeight);
    }
}

by implementing the IWidget interfacce on both our nodes and a collection of nodes it makes it trivial to calculate the total weight of our shipment, this is because whether it's an individual widget or a composite of widgets the weight property retrieves what it's suppose to. now obviously this is a contrived example and an actual implementation would be more complicated with many more fields and would require a lot more planing, but the jist of the pattern is here.