If there is no compelling reason (such as polymorphism) to make all the algorithms have the same interface (
execute()
), then I would actually prefer option 3, except that I'd only pass the state (a copy of it) to algorithm 2. This communicates that this specific algorithm requires additional, just-in-time information in order to run. If that's not feasible, then I'd consider other options.