我的工厂正在使用方法注入,因为我认为这是迄今为止最好的方法。此外,我怀疑在必须从依赖对象中调用其Create
方法后,这是一件好事。
我可能想到的同时继续使用参数化工厂的唯一方法Create
的方法,是直接在注入的依赖关系的MainPresenter
,以便它可以与依赖关系的方法提供,并我不喜欢它。它不喜欢它,因为MainPresenter
不依赖于ICustomerManagementView
和ICustomerDetailPresenterFactory
,它依赖于它。所以我觉得我这样做是在破坏自己的代码。
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"))
)
);
}
}
所以我想,是它最好地实现内与它的ICustomerManagementPresenterFactory
,并结合实施者我的CompositionRoot
,这样我可以提供通过构造器注入这些依赖于Create
方法不再提出任何论据,或者我不应该提出任何论据?
我喜欢编写一个简单的界面是Ninject为我工厂所做的一切,并且不需要代码来构建所需类型的实例。此外,当要创建的类的构造函数使用构造函数注入时,似乎不可能将简单的工厂接口绑定为工厂,并且需要手动实现工厂接口。
我得对错了什么?
答案 0 :(得分:1)
事实上,您根本不需要将参数传递给工厂Create
方法 - 除非它们是需要“向下”传递的参数,因为它们不能在组合中绑定root(例如输入值)。但是,将这些参数传递给构造函数通常是代码气味。大多数情况下,最好将这些参数传递给方法而不是构造函数(例如:Adder.Add(5,3);
,而不是new Adder(5, 3).ComputeResult();
。
现在考虑以下示例,该示例完美无缺:
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>();
即使Bar
有两个构造函数参数,生成的IBarFactory
的{{1}}方法也没有指定。没问题,ninject会自动解决它。
现在让我举个例子Create()
实际产生的结果。考虑工厂:
.ToFactory()
会导致(注释:它是通过拦截器实现的,而不是通过编织实现的,所以示例是简化):
public interface ISomeFactory
{
ISomething Create(string parameter1);
}
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);
}
}
告诉ninject将ConstructorArgument
的值传递给名为“parameter”的ctor参数。
所有其他参数“照常”解决。如果无法解析构造函数参数(既不作为参数传递也不作为参数传递),则ninject将抛出一个异常,指出该参数无法解析。