First of all, the open source engine is officially not supported and also discontinued, version 5.1.1 is the latest ever to be released. However, here are some hints.
1. Denormalizer is definitely a cleaner way in terms of not altering the source code.
2. If you need to re-use the Denormalizer along with certain other "servicing" components, you can use subgraphs (v. 5.1.1) to make the whole logic reusable instead of creating the same pattern over and over.
3. If you still intend to rather code the function for the aggregator, you should be able to achieve that by creating your own class (the function) that extends AggregateFunction and register it in the FunctionRegistry constructor. This way your function will look like every other aggregator function to the Aggregator.
The reason why there is no easier way to create custom aggregation functions is that the Aggregator simply wasn't designed to be extendable with custom functions.
Please note that altering the source code is without any warranty and we cannot support any issues related to the open source engine and/or the custom modifications.