Hi Russell,
Maybe the concrete case will help. I have a single entry point into which Commands can be posted, let's call it a CommandGateway. This gateway will do many things, the least of which will be to delegate the handling of the command to the command handler registered with the gateway. The strategy is 'how to handle a command'.
Now, the handler for :command-a needs a database for example. The handler for :command-b needs another collaborator.
CommandGateway has no idea about this and defines a defmulti called handle-command which dispatches on the :type of the command (which is really a trivial map).
The command handler for :command-a registers a defmethod for :command-a but how does the body of that defmethod access the database connection for example?
I can see a few options:
- give up on avoiding global state and have a bound 'system' register (i.e. a global/static service locator) - please no.
- don't use multi-methods for this and have CommandGateway have a map of predicate:handler. The handler for command-a would then register itself and use lexical scoping to access the required collaborators
- use multi-methods, but have a CommandAHandler which is a stateful record and retains its collaborators (i.e. the database) and extends itself to implement command-handler)
My question is really 'when does using types stop being idiomatic'. So far I have gotten surprisingly far using maps/sequences and passing collaborators around. Now it seems to use multi methods to dispatch the command I need the target of the dispatch to be stateful to remember its collaborators.
Might all be a storm in a teacup :), hence the clarity request.