Aggregate factory

Replaces #29 incorporating @kelvinj's work. This looks nothing like the original #29 so it has a new PR so that we can move on from here.