Given a layered architecture, where the business logic is isolated in a package from all other layers, like persistent storage, user interface, interfaces for various (vendor) remote services, etc, I am thinking to manage dependencies in the following way:
Within the library, all dependencies are injected manually via the constructor. This has the advantage (which in my opinion is big) that it makes tests more explicit, increasing their value as a documentation source.
For the other layers and plugins, I am thinking to inject manually only one object used for dependency lookup, which would make mocking easier. I doubt there would be only one object for all subsystems, I am merely thinking about really specific, small interfaces, and factory instances which implement one or more of those interfaces. How many interfaces such a factory implements is an implementation detail, I guess I would start with only one factory implementing all interfaces, and as the system evolves, I would pull out other factories and refactor accordingly (YAGNI). The interfaces (i.e. the signature of the constructors) would stay as they were before refactoring, thanks to interface segregation.
The business library gets its commands from outside via commands (think DDD).
- What do you think about this? Other advantages and disadvantages are welcome!
- Which other strategies for dependency management do you prefer in which situations and why?
Best Answer
You're going for something akin to (but not similar) Spring's ApplicationContextAware, where you pass ApplicationContext (which is a BeanFactory) via a setter, so it later can get beans it needs.
Generally it is a bad idea, if you only need to inject dependencies:
UserRepositoryFactory
which has a method likegetUserRepository
, I guess), it will be type safe, but I don't see the benefit in this solution, because it seems much easier to just inject dependencies without medium getter/wrapper/injector-objects. I think it would be just duplication of DI functionality.If I would make a plugin system, I would go with "stupid" plugins, which just implement some
SomethingPlugin
interface, and expect it's dependencies to be injected (via constructor or setters, which doesn't really matter) by the system, without any prior knowledge of anything outside.Example:
Then you register this plugin (via config file, I imagine), then somewhere in a "system level" code you instantiate this class, set dependencies (this part can be automated by Spring's or similar DI-container) and invoke
doPluginMagic()
.This way you still have small specific interfaces, but now as parts of a plugin API, which I think simplifies the whole thing. You can see what plugin can access by just looking on its' type declaration, and no additional "factories" have to be crafted.