Right now what I see is the following chain of dependencies:
client->controller->adapter->reader->controller
That does create a circular dependency.
You use Dependency Injection to achieve Dependency Inversion. That is, that higher level code does not dependent on the implementation of lower level code.
Looking at the chain, we can attest that there is a piece of code, either the controller or the text reader, that is both high and low level.
If the client does need to use directly the text reader then it cannot be that the adapter uses it as well, as you would need to inject it further up. Rather you will be injecting the adapter into the text reader. And then injecting the text reader into the client.
But if we do that, and we keep the injection of the controller both on the client and the text reader, are we not, then, exposing incorrectly functionality? Because you are saying both that the text reader is of the same level than the controller, and that the controller is at a lower level than the text reader (as it is injected)
Finally, why does the client need to access the text reader used by the adapter? If there is really something that is needed you can provide a pass through method that doesn't expose the fact that you have the text reader somewhere down there.
Check which functionality is going to be lower level (which one actually does the writing/reading) and which one does the high level stuff. Order them higher to level and inject lower into higher.
Without looking at the code,I am imagining that the actual order would be
client->controller->adapter->text read/write
And that in fact the text reader/writer doesn't need to know about the controller because it is the one reading/writing directly from/to the device. Any information that the controller has that the text reader/writer needs will be passed through parameters.
Ok, those are many questions you have and I guess some of the points can be approached in more than one way.
Creating the injector is not cheap. Guice will do some analysis to detect errors as well as create all singletons. So you should create the injector at startup.
I usually have a single injector for my application.
Regarding your question 1.:
Yes the injector can be injected. But I see it as a bad practice. Reason for this is that calls to injector.getInstance()
and injector.injectMembers()
make it hard to reason about the dependencies of a class.
- if you need to create more than one instance or you need to control the time when an instance is created inject a Provider instead of X.
- if the object you want to create needs both runtime parameters and dependencies use assisted inject.
- for many kinds of objects (like DTO, POJO and alike) its absolutely ok to create them by calling new or a conventional factory.
In this sense the injector is implicitly available to any instance created by Guice this includes the API user.
And finally AOP.
Aspects are a powerful feature but also can hide some of the business logic I suggest to use them only for very repetitive tasks which all developers know well.
Also take into account that aspects only work on:
- instances created by Guice
- non private, non static, non private methods
Finally, Guice won't inform you if you add an annotation to either of the above. Your aspect will silently be ignored
Best Answer
The benefit isn't that the interface declares the members and methods that a client needs--which is exactly what a concrete class can do. The benefit is that a concrete class can implement an interface, which allows you to swap out the dependency at run-time. For testing, you may want to pass in a mock implementing the same interface, but without all the overhead of the usual class (database calls, perhaps). Your class only depends on an interface, but the implementation is left for the DI/IoC container to inject.