When you create your bindings, don't tell Guice that this is a
singleton. Then, Guice will create a new instance for each user.
> Or in this case, do I even NEED to use Guice to create
> the calculator instances since this is a factory. Guice would just
> inject the needed dependencies to the factory. I'm confused about
> "Guice replacing all instances of 'new'" in our code. Does that hold
> true everywhere or are there places where you would expect to 'new' a
> class?
Think about things from the perspective of your calling user for a
moment, and you realize:
* There is no need for the calling user to know whether
the calculator is a singleton or not.
* There is no need for the calling user to know
how the calculator got created (factory, service
lookup, or some other mechanism).
In addition, from the calculator implementor's point of view, you
don't have to waste the effort to create a factory if you don't need
one. You can change your mind later (singleton to per request,
instance to provider) later as well, with zero impact on the calling
users. Plus, it's much easier to set up unit tests without having to
mock both a calculator implementation and a factory.
>
> public class CalculatorFactory {
>
> private final Map<UserGroup, ICalculator> m_calculators;
>
> public CalculatorFactory(SomeObject dependency1, SomeObject
> dependency2, SomeObject dependency3) {
> m_calculators = new HashMap<UserGroup, ICalculator>();
> m_calculators.put(UserGroup.A, new ACalculator(dependency1,
> dependency2, dependency3);
> m_calculators.put(UserGroup.B, new BCalculator(dependency1);
> m_calculators.put(UserGroup.C, new CCalculator(dependency1);
> }
>
> // Depending on which group a user belongs to,
> // a different type of calculator will be returned
> public ICalculator loadCalculator(UserGroup userGroup) {
> return m_calculators.get(userGroup);
> }
>
> }
One way you could make this either-or kind of choice would be to
provide a "binding annotation" that a caller can also use to tell
Guice what kind of calculator it needs. For example, if you have two
groups ("Mechanical" and "Electric") which determines which kind they
need, one caller might say:
@Inject @Mechanical Calculator calculator;
while another could say:
@Inject @Electric Calculator calculator;
(Sorry, couldn't resist :-).
The other way to deal with conditional creation would be to bind
Calculator to a Provider<Calculator> (a kind of factory) instead. The
provider would have some way to figure out what group the user is
(perhaps through getting a User object injected to it), Then, Guice
will call the provider's get() method when it needs an instance
(optionally injecting things into the provider class as needed).
Again, note that the *user* of a Calculator need not understand how
the right instance was picked -- it just gets to worry about actually
using it.
Craig McClanahan