mardi 14 mars 2017

Hierarchical Data - Composite Pattern C#

I have a recurring pattern that I see in some of the reports that I have to generate. These reports are date range based reports and need to be aggregated by different levels.

For the sake of simplicity, let's assume that this report produces a title and a quota at the leaf node level (lowest level). At the line item level (which is a collection of various leaf nodes), I would like to aggregate the Quota and provide a separate title. These line items would further roll up to another level which would again aggregate the quota and have a unique title.

So the report would be something like this:

ROOT LEVEL | Title = "Main Report" | Quota = 100
   Month Level    | Title = "Jan" | Quota = 100
     Week Level   | Title = "Week 1" | Quota = 25
     Week Level   | Title = "Week 2" | Quota = 75

Is there way for me to build this using a composite pattern? I have tried numerous approaches. Most of them fall short because I cannot effectively aggregate/sum up the quota to the higher level.

I can build an interface like so:

public interface IInventoryReportItem
{ 
    string Title { get; set; }
    int Quota { get; set; }
}

Then I can build a Line Item like so:

public class LineItem : IInventoryReportItem

I can also build a collection like so:

 public class LineItems : IList<IInventoryReportItem>, IInventoryReportItem
{
    private readonly List<IInventoryReportItem> _subLineItems;

    public LineItems()
    {
        _subLineItems = new List<IInventoryReportItem>();
    }

And my report would be like so:

public class InventoryReport
{
    public DateRange DateRange { get; set; }
    public LineItems LineItems { get; set; }

}

I can build the report easily in a hierarchical fashion now, but I still need to call the aggregation functions from the outside as opposed to it auto-calculating this for me:

var report = new InventoryReport();

        var week1Days = new LineItems
        {
            new LineItem {Quota = 20, Title = "Day 1"},
            new LineItem {Quota = 10, Title = "Day 2"}
        };

        var week2Days = new LineItems
        {
            new LineItem {Quota = 10, Title = "Day 1"},
            new LineItem {Quota = 10, Title = "Day 2"}
        };

        var week1 = new LineItems {week1Days};
        week1.Quota = week1.Sum(x => x.Quota);
        week1.Title = "Week1";


        var week2 = new LineItems {week2Days};
        week2.Quota = week2.Sum(x => x.Quota);
        week2.Title = "Week2";

        var month1 = new LineItems(new List<IInventoryReportItem> {week1, week2});
        month1.Title = "January";
        month1.Quota = month1.Sum(x => x.Quota);

        report.LineItems = new LineItems(new List<IInventoryReportItem> {month1});

Is there a way I can still have the flexibility of adding either a single line item or a range of items, and it also auto-calculate/aggregate the data for me using the composite?

Any help would be great!

Thank You, Anup

Aucun commentaire:

Enregistrer un commentaire