Your question is about dependency injection, but it’s more about polymorphism. In Java, polymorphism is implemented using inheritance. Another way to refer to this is single dispatch by type. You provide an instance of the interface and which concrete implementation is used doesn’t matter to the caller.
Dependency injection in Java works by reflecting over your interfaces to determine who is dependent on whom. Since a Java signature is the method name, order and type of the arguments, the return type, and annotations (parameter names are normally erased unless you configure the compiler to include them), the DI library can build a dependency graph so it can bring up everything in the correct order, and inject a class’ dependencies upon instantiation or field/property injection.
In Clojure we can only rely on the name and the arity (number of arguments) of the function. The compiler can’t enforce the types, or even that you called with the correct ordering of arguments. We also have more ways to do polymorphism in Clojure:
- By name: What you’re describing above, require N different namespaces that have the same function names/arities. You can dynamically require the correct namespace based on some condition (config, function param, etc.).
- Protocols: Most similar to Java interfaces, but protocols only dispatch on type, name, and arity. Existing types can also be extended to support protocols after the fact.
- Multi-method: Multiple dispatch, using a custom dispatch function. It also supports complex hierarchies that can’t be described in Java’s inheritance structure.
- Higher order functions: Pass a function as an argument into your function, which does a specific implementation.
Quick intro to Clojure polymorphism: https://8thlight.com/blog/myles-megyesi/2012/04/26/polymorphism-in-clojure.html
Any dependency injection library for Clojure would have to use one of those methods or something else entirely.
I believe these are the most popular libs to achieve dependency injection in Clojure, and they all take a slightly different approach:
Also, I would encourage you to forget most of your Java design patterns when working in Clojure. Here’s some good examples of Clojure versions of popular patterns: http://mishadoff.com/blog/clojure-design-patterns/