Is there an alternative to bastard injection? (AKA poor man's injection via default constructor)
As far as I understand, this question relates to how to expose a loosely coupled API with some appropriate defaults. In this case, you may have a good Local Default, in which case the dependency can be regarded as optional. One way to deal with optional dependencies is to use Property Injection instead of Constructor Injection - in fact, this is sort of the poster scenario for Property Injection.
However, the real danger of Bastard Injection is when the default is a Foreign Default, because that would mean that the default constructor drags along an undesirable coupling to the assembly implementing the default. As I understand this question, however, the intended default would originate in the same assembly, in which case I don't see any particular danger.
In any case you might also consider a Facade as described in one of my earlier answers: Dependency Inject (DI) "friendly" library
BTW, the terminology used here is based on the pattern language from my book.
My trade-off is a spin on @BrokenGlass:
1) Sole constructor is parameterized constructor
2) Use factory method to create a ThingMaker and pass in that default source.
public class ThingMaker {
public ThingMaker(IThingSource source){
_source = source;
}
public static ThingMaker CreateDefault() {
return new ThingMaker(new DefaultThingSource());
}
}
Obviously this doesn't eliminate your dependency, but it does make it clearer to me that this object has dependencies that a caller can deep dive into if they care to. You can make that factory method even more explicit if you like (CreateThingMakerWithDefaultThingSource) if that helps with understanding. I prefer this to overriding the IThingSource factory method since it continues to favor composition. You can also add a new factory method when the DefaultThingSource is obsoleted and have a clear way to find all the code using the DefaultThingSource and mark it to be upgraded.
You covered the possibilities in your question. Factory class elsewhere for convenience or some convenience within the class itself. The only other unattractive option would be reflection-based, hiding the dependency even further.
One alternative is to have a factory method CreateThingSource()
in your ThingMaker
class that creates the dependency for you.
For testing or if you do need another type of IThingSource
you would then have to create a subclass of ThingMaker
and override CreateThingSource()
to return the concrete type you want. Obviously this approach only is worth it if you mainly need to be able to inject the dependency in for testing, but for most/all other purposes do not need another IThingSource
I vote for #3. You'll be making your life--and the lives of other developers--easier.
If you have to have a "default" dependency, also known as Poor Man’s Dependency Injection, then you have to initialize and "wire" the dependency somewhere.
I will keep the two constructors but have a factory just for the initialization.
public class ThingMaker
{
private IThingSource _source;
public ThingMaker(IThingSource source)
{
_source = source;
}
public ThingMaker() : this(ThingFactory.Current.CreateThingSource())
{
}
}
Now in the factory create the default instance and allow the method to be overrided:
public class ThingFactory
{
public virtual IThingSource CreateThingSource()
{
return new DefaultThingSource();
}
}
Update:
Why using two constructors: Two constructors clearly show how the class is intended to be used. The parameter-less constructor states: just create an instance and the class will perform all of it's responsibilities. Now the second constructor states that the class depends of IThingSource and provides a way of using an implementation different than the default one.
Why using a factory: 1- Discipline: Creating new instances shouldn't be part of the responsibilities of this class, a factory class is more appropriate. 2- DRY: Imagine that in the same API other classes also depend on IThingSource and do the same. Override once the factory method returning IThingSource and all the classes in your API automatically start using the new instance.
I don't see a problem in coupling ThingMaker to a default implementation of IThingSource as long as this implementation makes sense to the API as a whole and also you provide ways to override this dependency for testing and extension purposes.