Here is a concrete case, implemented by the ASP.NET Web Api team itself on GitHub: link
I myself have applied the same here template.
Briefly, the two links above show a variation of the "Parameter Object" pattern.
Public constructors of the class receive either their dependencies directly, or another object containing their dependencies.
Both public constructors wrap arguments in an instance of IDependencyProvider
, which is passed to a private constructor that extracts dependencies and treats them uniformly. This builder is considered an implementation detail, the clients do not need to know about it, and therefore it is private.
public class MyClass
{
private readonly string _dependency1;
private readonly string _dependency2;
public MyClass(string dependency1, int dependency2)
: this(new DirectDependencyProvider(dependency1, dependency2))
{
}
public MyClass(Container container)
: this(new ContainerDependencyProvider(container))
{
}
//constructor privado
private MyClass(IDependencyProvider provider)
{
_dependency1 = provider.Dependency1;
_dependency2 = provider.Dependency2;
//etc, fazer alguma coisa com as duas dependencias
}
private interface IDependencyProvider
{
string Dependency1 { get; }
int Dependency2 { get; }
}
private class DirectDependencyProvider : IDependencyProvider
{
private readonly string _dependency1;
private readonly int _dependency2;
public DirectDependencyProvider(string dependency1, int dependency2)
{
_dependency1 = dependency1;
_dependency2 = dependency2;
}
public string Dependency1
{
get { return _dependency1; }
}
public int Dependency2
{
get { return _dependency2; }
}
}
private class ContainerDependencyProvider : IDependencyProvider
{
private readonly Container _container;
public ContainerDependencyProvider(Container container)
{
if(container == null)
throw new ArgumentNullException("container");
_container = container;
}
public string Dependency1
{
get { return _container.StringStuff; }
}
public int Dependency2
{
get { return _container.IntStuff; }
}
}
}
Note that the IDependencyProvider
interface and its implementations are private types.
The alternative would be to use a private initialization method, but we would have to sacrifice the fields readonly
and the guarantee of its immutability. This is a sacrifice that can be avoided.
public class MyClass
{
private string _dependency1;
private string _dependency2;
public MyClass(string dependency1, int dependency2)
{
Initialize(dependency1, dependency2);
}
public MyClass(Container container)
{
if(container == null)
throw new ArgumentNullException("container");
Initialize(container.StringStuff, container.IntStuff);
}
private void Initialize(string dependency1, int dependency2)
{
_dependency1 = dependency1;
_dependency2 = dependency2;
}
}