views:

190

answers:

4

When dealing with objects that require data known only at runtime, such as a username and password, where should object instantiation happen: by using new, in a factory, or in a DI container?

For example, I could just new an object once I have the data:

UserCredentials creds =
    new UserCredentials(dialog.getUsername(), dialog.getPassword());

Or, I could use a factory:

UserCredentials creds =
    CredentialsFactory.create(dialog.getUsername(), dialog.getPassword());

Or, I could use a provider within a DI container (which in this case would essentially be a parameter-driven factory). [Sample code omitted.]

It seems both wrong to use the DI container for something so simple yet it also seems wrong not to use it to its fullest.

A: 

For me, I use DI for creating a more loose coupling between objects. If your object dependencies get very affected by creating an object using new, then I don't see why you couldn't use DI or relay object creation to a factory. This gives you more control and keeps your classes loosley coupled.

It really depends when and where you'll need this object and if there will be unnecessary dependencies as a result.

Tony
A: 

If you already have a DI container set up for your application then use this approach. If not, use a factory method.

darren
+3  A: 

As always, it depends, but as a general rule, a static factory like your second option is only rarely a good idea.

newing up a UserCredential object seems like a fair choice because the UserCredentials class looks like a self-contained, concrete class that can be fully instantiated with all its invariants from the username and password.

In other cases, the type you would like to create may represent an abstraction in itself. If this is the case, you can't use the new keyword, but must use an Abstract Factory instead.

Using an Abstract Factory is often very valuable because it allows you to compose an instance from a combination of run-time values and other dependencies. See here for more information.

Using an Abstract Factory also helps with unit testing because you can simply test that the return value or end state or whatever you care about is related to the output of the Abstract Factory - for which you can easily supply a Test Double because it is... abstract.

Mark Seemann
I hadn't even consciously thought about static factory versus abstract factory. Thanks for the value-additive comment in that regard.
Kaleb Pederson
+1  A: 

The google testing blog has a post which tries to answer this question. The basic idea is that you can classify each of your classes as a "newable" or "injectable", and that it is OK to just "new up" the newables.

I distinguish 2 main categories of "newables":

  • values like int, string, DateTime, etcetera.
  • entities like Customer, Order, Employee, etcetera. I think your UserCredentials class falls under this heading.

It's important to realize that newables can have (testable) behavior. If you make the mistake of thinking that newables shouldn't have any behavior or unit tests, you'll end up with the anemic domain model anti-pattern.

A side-effect of having "newables" with behavior is that this behavior can't be abstracted away in the unit tests of your injectables. This is OK; it is normal to have some strong coupling between your domain model and the rest of your application.

Also, newables are allowed to know about injectables, but they only cooperate with them transiently. For example, UserCredentials should not take a IUserDatabase as a constructor argument. Instead, there might be a UserCredentials.Verify(IUserDatabase) method.

edit: I'm currently not so sure anymore about what I wrote above. Entities can also be constructed via (injectable) factories instead of calling their constructor directly. The factory implementation can then inject things in the entity.

Wim Coenen
Your "anemic domain model" link refers to the 'to new or not to new' article.
Kaleb Pederson
thanks, it's fixed now.
Wim Coenen