Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default values for constructor arguments in a library project

I am writing a library that will provide a collection of public types to its consumers.

I want to make types from this library dependency injection friendly. This means that every class needs to have a constructor through which it is possible to specify every single dependency of the object being initialized. I also want the library to adhere to the convention over configuration principle. This means that if a consumer wants the default behavior, he may use a parameterless constructor and the object will somehow construct the dependencies for itself.

In example (C#):

public class Samurai {

    private readonly IWeapon _weapon;

    // consumers will use this constructor most of the time
    public Samurai() {
        _weapon = ??? // get an instance of the default weapon somehow
    }

    // consumers will use this constructor if they want to explicitly
    //   configure dependencies for this instance
    public Samurai(IWeapon weapon) {
        _weapon = weapon;
    }
}

My first solution would be to use the service locator pattern.

The code would look like this:

...
public Samurai() {
    _weapon = ServiceLocator.Instance.Get<IWeapon>();
}
...

I have a problem with this, though. Service locator has been flagged as an anti-pattern (link) and I completely agree with these arguments. On the other hand, Martin Fowler advocates use of the service locator pattern exactly in this situation (library projects) (link). I want to be careful and eliminate the possible necessity to rewrite the library after it shows up that service locator really was a bad idea.

So in conclusion - do you think that service locator is fine in this scenario? Should I solve my problem in a completely different way? Any thought is welcome...

like image 278
Tomas Avatar asked Mar 28 '12 20:03

Tomas


1 Answers

If you want to make life easier for users who are not using a DI container, you can provide default instances via a dedicated Defaults class which has methods like this:

public virtual Samurai CreateDefaultSamurai()
{
   return new Samurai(CreateDefaultWeapon());
}

public virtual IWeapon CreateDefaultWeapon()
{
   return new Shuriken();
}

This way you don't need to pollute the classes themselves with default constructors, and your users aren't at risk of using those default constructors unintentionally.

like image 61
Wim Coenen Avatar answered Oct 01 '22 00:10

Wim Coenen