class BatchingExecutor implements CommandExecutor {

    private final BatchHelper<RemoteCommand<?>, CommandResult<?>, MultiCommand, CommandResult<MultiResult>> batchingHelper;
    private final CommandExecutor wrappedExecutor;
    private final OptimizationListener listener;

    private final Function<List<RemoteCommand<?>>, MultiCommand> taskCombiner = new Function<>() {
        @Override
        public MultiCommand apply(List<RemoteCommand<?>> commands) {<FILL_FUNCTION_BODY>}
    };

    private final Function<MultiCommand, CommandResult<MultiResult>> combinedTaskExecutor = new Function<>() {
        @Override
        public CommandResult<MultiResult> apply(MultiCommand multiCommand) {
            return wrappedExecutor.execute(multiCommand);
        }
    };

    private final Function<RemoteCommand<?>, CommandResult<?>> taskExecutor = new Function<>() {
        @Override
        public CommandResult<?> apply(RemoteCommand<?> remoteCommand) {
            return wrappedExecutor.execute(remoteCommand);
        }
    };

    private final BiFunction<MultiCommand, CommandResult<MultiResult>, List<CommandResult<?>>> combinedResultSplitter = new BiFunction<>() {
        @Override
        public List<CommandResult<?>> apply(MultiCommand multiCommand, CommandResult<MultiResult> multiResult) {
            return multiCommand.unwrap(multiResult);
        }
    };

    public BatchingExecutor(CommandExecutor originalExecutor, OptimizationListener listener) {
        this.wrappedExecutor = originalExecutor;
        this.listener = listener;
        this.batchingHelper = BatchHelper.create(taskCombiner, combinedTaskExecutor, taskExecutor, combinedResultSplitter);
    }

    @Override
    public <T> CommandResult<T> execute(RemoteCommand<T> command) {
        return (CommandResult<T>) batchingHelper.execute(command);
    }

}

            if (commands.size() > 1) {
                listener.incrementMergeCount(commands.size() - 1);
            }
            return MultiCommand.merge(commands);
        
<no_super_class>