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.
Dependency Injection is more of a architectural pattern for loosely coupling software components. Factory pattern is just one way to separate the responsibility of creating objects of other classes to another entity. Factory pattern can be called as a tool to implement DI.
The fact your class has so many dependencies indicates there are more than one responsibilities within the class. Often there is an implicit domain concept waiting to be made explicit by identifying it and making it into its own service. Generally speaking, most classes should never need more than 4-5 dependencies.
Dependency injection helps to develop testable code, allowing developers to write unit tests easily. You can use mock databases with dependency injection, and test your application without affecting the actual database.
As always, it depends, but as a general rule, a static factory like your second option is only rarely a good idea.
new
ing 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.
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":
int
, string
, DateTime
, etcetera.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With