On Monday, November 11, 2013 10:03:56 AM UTC-5, Alan Darkworld wrote:
>
>
> *1)* The Injector becomes a sort of "main static factory" for the entire
> application. However, Guice does not instance-control the injector - in
> other words, Injector#getInstance is not static. How do you share your
> injector across all classes in your application such that it's easy to
> access? The easiest thing I can think of is to create it once at the start
> of the program and then make it available through a static field, but that
> just doesn't feel "right" to me.
>
Not being static is kind of the point - you *should* be able to instantiate
a properly designed application twice in the same VM without them
interfering with each other - it's a good test (IMO) of the quality of your
code. Think of the entire object graph that makes up your application as
hanging by a thread (the clothing kind, not the programming kind) of object
references - literally a reference chain of objects referring to each other
and keeping the whole application from being garbage collected. You want
that thread to be as thin as possible, so that if it is cut, the whole
application vanishes. If you can do both of those things, it proves that
your code does not leak memory and does not have side-effects that might
affect future additions to it or other code cohabitating in the same VM.
If the injector were static, that would be assuming there is only one per
Java virtual machine. Yet you can have libraries which use Guice
under-the-hood without exposing it to anything. Some other code also using
Guice should not have the opportunity to interfere with that. If the
injector were shared, it would.
Statics are global state - global variables. If some code needs to use
one, it is usually for purposes of (pretend) decoupling of two things which
depend on each other. Guice offers an alternative way of expressing that
dependency which does not require state to be global.
> *2)* I can see that DI is handy if all objects have no-argument default
> constructors. But most of the time, this is not the case, especially with
> immutable objects that need to check their invariants in their constructor.
> Consider for example an immutable "DateRange" class with the invariant
> "start date < end date". The only valid constructor for this class has two
> parameters (the dates), yielding a client code like:
>
> long start = calculateStart(); // calculates the start time based on
> user input (result is dynamic)
> long end = calculateEnd(); // calculates end time based on user input
> (result is dynamic)
> DateRange period = new DateRange(start, end); // throws
> IllegalArgumentException if start > end), need to replace this line by
> Depencency Injection
>
> How would something like this translate into the Dependency Injection
> idiom? I can clearly see DI working for the Java Beans pattern, but what
> about the immutable case? I've had a look at the Guice Documentation, but I
> couldn't spot an answer to this.
>
As others have pointed out, Guice is really more about creating a graph of
objects on startup (or whenever they are demanded), rather than dealing
with data that appears at runtime. If you really want this sort of thing,
there are ways to do it (custom scopes, factories, assisted inject, tricks
with Provider) - it can be useful if you want to have generic or pluggable
logic that deals with input. But that's overkill for a lot of cases - the
goal is not to never ever call a constructor again.
*3)* For many years, several books (including the excellent "*Effective
> Java*") have gone to great lenghts explaining how to keep our class
> invariants safe from both malicious access and careless programmers
> (including client use and subclassing). By applying DI, we forfeit the
> control over our fields, we give up on encapsulation. From my point of
> view, with DI the focus has shifted from "*This class will work, no
> matter how much you mistreat it*" to "*It works if you treat it right,
> otherwise it's your own fault*". What implications does that have for
> software quality? We sure gain a lot in terms of configurability (create a
> new subclass, introduce it in the module and you're all set), but what do
> we lose with respect to safety and contracts? This is actually my main
> concern about DI and the very reason why I can't yet wrap my head around
> it. Can somebody provide a reason why my concerns are without cause? Please
> do!
>
You don't really forfeit control over your fields unless you want to.
First, you *can* inject into private fields if you feel like it - Guice
will do it. I don't think that's actually a good idea, but it's possible.
For that, you do give up the ability to have those fields be final - which
to me is unacceptable - if it can mutate, you have to assume it does
mutate, so anything I don't actually intend to be mutable should not be.
The final keyword is a great way to let the compiler help prove your
program is correct and reduce the number of possible states your program
might have.
You do not have to give up immutability to use Guice; you see field
injection in the wild mostly because many frameworks are old and a lot of
Java developers haven't learned the importance of immutability, and a huge
number of frameworks out there are based on the beans pattern. That's more
an artifact of early Java developers not knowing any better, and later ones
copying the patterns they saw used by earlier ones.
A more sensible approach is to use constructor injection - @Inject public
MyClass(Thing thing) {...} - then you can assign what your class is passed
to final fields in it. You can make your constructors public or not. I
can have, in the same package
@ImplementedBy(FooImpl.class)
public interface Foo {
...
}
class FooImpl {
private final Bar bar;
@Inject
FooImpl(Bar bar) { this.bar = bar; }
}
and Guice will happily instantiate FooImpl when something needs a Foo. On
the one hand, Guice is breaking some Java visibility rules to do that, but
on the other hand, you can hide implementation even more than without it.
But really, your fields are going to be assigned by something, if they need
to be assigned for your program to work. The values can either be provided
by a person writing code to construct an object or call setters on it, or
it can be done by Guice, which will always do it in a consistent way.
IMHO, the likelihood of bugs is higher due to human error.
If you write a class which will work right even if you mistreat it, that
characteristic of the class does not change because of what instantiated it.
-Tim
--
You received this message because you are subscribed to the Google Groups
"google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/google-guice.
For more options, visit https://groups.google.com/groups/opt_out.