My factory is using method injection because I thought this was the best way to make it so far. Besides, I doubt it is a good thing after having to call on its Create
method from within a dependent object.
The only way I might think of whilst continuing to use the parameterized factory Create
method, is to inject the dependencies directly in the MainPresenter
so that it may provide with the dependencies to the method, and I dislike it. It dislike it because it is not the MainPresenter
that depends on the ICustomerManagementView
and the ICustomerDetailPresenterFactory
, it's its dependency. So I would feel like I'm sabotaging my own code by doing so.
MainPresenter
public class MainPresenter : Presenter<IMainView>, IMainViewUiHandler {
public MainPresenter(IMainView view
, ICustomerManagementPresenterFactory customerManagementFactory)
: base(view) {
this.customerManagementPresenterFactory = customerManagementPresenterFactory;
}
public void ManageCustomers() {
// The following line is causing trouble.
// As you can see per the ICustomerManagementPresenterFactory code sample,
// the Create() method takes two parameters:
// 1. ICustomerManagementView, and
// 2. ICustomerDetailPresenterFactory
// Hence I have to provide the dependencies manually, I guess. Which is
// something to avoid at any cost.
var customerManagementPresenter = customerManagementPresenterFactory.Create();
customerManagementPresenter.ShowView();
}
}
ICustomerManagementPresenterFactory
public interface ICustomerManagementPresenterFactory {
// Here. Though I ask Ninject to inject my dependencies, I need to
// provide values to the parameters when calling the method from within
// the MainPresenter class. The compiler won't let me do otherwise! And
// this makes sense!...
[Inject]
CustomerManagementPresenter Create(ICustomerManagementView view
, ICustomerDetailPresenterFactory factory);
}
IMainView
public interface IMainView : IView, IHasUiHandler<IMainViewUiHandler> {
}
IMainViewUiHandler
public interface IMainViewUiHandler : IUiHandler {
void ManageCustomers();
}
IUiHandler
public interface IUiHandler {
}
IHasUiHandler
public interface IHasUiHandler<H> where H : IUiHandler {
H Handler { set; }
}
MainForm
public partial class MainForm : Form, IMainView {
public MainForm() { InitializeComponent(); }
public IMainViewUiHandler Handler { private get { return handler; } set { setHandler(value); } }
}
CompositionRoot
public class CompositionRoot {
private CompositionRoot() { }
public static IKernel BuildObjectGraph() {
IKernel kernel = new StandardKernel();
BindFactories(kernel);
BindViews(kernel);
}
private static void BindFactories(IKernel kernel) {
kernel.Bind(services => services
.From(AppDomain.CurrentDomain
.GetAssemblies()
.Where(a => !a.FullName.Contains("Tests")))
.SelectAllInterfaces()
.EndingWith("Factory")
.BindToFactory()
);
}
private static void BindViews(IKernel kernel) {
kernel.Bind(services => services
.From(AppDomain.CurrentDomain
.GetAssemblies()
.Where(a => a.FullName.Contains("Windows")
&& !a.FullName.Contains("Tests"))
.SelectAllClasses()
.EndingWith("Form")
.BindSelection((type, baseType) => type
.GetInterfaces()
.Where(iface => iface.Name.EndsWith("View"))
)
);
}
}
So I wonder, is it best to implement the ICustomerManagementPresenterFactory
and bind the implementer with it within my CompositionRoot
, so that I could provide those dependencies through constructor injection to the Create
method which shall no longer take any arguments, or shall I make it otherwise?
What I like of writing a simple interface is that Ninject does it all for me to a factory, and no code is necessary to build an instance of the desired type. Besides, when the constructor of the class to be created uses constructor injection, it seems like it is impossible to have a simple factory interface bound as a factory, and one need to implement the factory interface by hand.
What did I get right/wrong?
As a matter of fact you don't need to pass parameters to the factory Create
method at all - except in case they are parameters which need to be passed "down" because they cannot be bound in the composition root (for example an input value). However, passing such parameters to constructors is usually a code smell. Mostly, it's a better idea to pass these parameters to methods instead of constructors (for example: Adder.Add(5,3);
, not new Adder(5, 3).ComputeResult();
.
Now consider the following example, which works perfectly fine:
public class Dependency1 { }
public interface IDependency2 { }
public class Dependency2 : IDependency2 { }
public interface IBar { }
public class Bar : IBar
{
public Bar(Dependency1 d1, IDependency2 d2) { }
}
public interface IBarFactory
{
IBar Create();
}
var kernel = new StandardKernel();
kernel.Bind<IBarFactory>().ToFactory();
kernel.Bind<IBar>().To<Bar>();
kernel.Bind<Dependency1>().ToSelf();
kernel.Bind<IDependency2>().To<Dependency2>();
var factory = kernel.Get<IBarFactory>();
var bar = factory.Create();
bar.Should().BeOfType<Bar>();
even though Bar
takes two constructor arguments, the generated IBarFactory
's Create()
method does not specify so. No problem, ninject will resolve it automatically.
Now let me give you an example what .ToFactory()
actually results in. Consider the factory:
public interface ISomeFactory
{
ISomething Create(string parameter1);
}
Will result in (remark: it's realised by interceptors and not by weaving it, so the example is a simplificiation):
public class SomeFactory : ISomeFactory
{
private readonly IResolutionRoot resolutionRoot;
public SomeFactory(IResolutionRoot resolutionRoot)
{
this.resolutionRoot = resolutionRoot;
}
public ISomething Create(string parameter1)
{
this.resolutionRoot.Get<ISomething>(new ConstructorArgument("parameter1", parameter1);
}
}
The ConstructorArgument
tells ninject to pass the value of parameter1
to the ctor-parameter named "parameter".
All other parameters are resolved "as usual". If a constructor parameter cannot be resolved (neither passed as parameter nor bound) ninject will throw an exception stating that the parameter cannot be resolved.