我习惯于创建我自己的工厂(如图所示):
public class ElementFactory
{
public IElement Create(IHtml dom)
{
switch (dom.ElementType)
{
case "table":
return new TableElement(dom);
case "div":
return new DivElement(dom);
case "span":
return new SpanElement(dom);
}
return new PassthroughElement(dom);
}
}
我终于开始在我当前的项目中使用IoC容器(AutoFac),我想知道是否有一些使用AutoFac优雅地实现同样功能的神奇方法?
答案 0 :(得分:23)
简短回答:是的。
更长的答案:首先,在类Foo被注册为IFoo实现的简单情况下,构造函数参数或类型Func<IFoo>
的属性将由Autofac自动解析,无需额外布线。 Autofac将注入一个在调用时基本上执行container.Resolve<IFoo>()
的委托。
在像你这样的更复杂的情况下,返回的确切结果是基于输入参数,你可以做两件事之一。首先,您可以将工厂方法注册为其返回值,以提供参数化分辨率:
builder.Register<IElement>((c, p) => {
var dom= p.Named<IHtml>("dom");
switch (dom.ElementType)
{
case "table":
return new TableElement(dom);
case "div":
return new DivElement(dom);
case "span":
return new SpanElement(dom);
}
return new PassthroughElement(dom);
});
//usage
container.Resolve<IElement>(new NamedParameter("dom", domInstance))
这不是类型安全的(domInstance不会被编译器检查以确保它是一个IHtml),也不是很干净。相反,另一种解决方案是将工厂方法实际注册为Func:
builder.Register<Func<IHtml, IElement>>(dom =>
{
switch (dom.ElementType)
{
case "table":
return new TableElement(dom);
case "div":
return new DivElement(dom);
case "span":
return new SpanElement(dom);
}
return new PassthroughElement(dom);
});
public class NeedsAnElementFactory //also registered in AutoFac
{
protected Func<IHtml,IElement> CreateElement {get; private set;}
//AutoFac will constructor-inject the Func you registered
//whenever this class is resolved.
public NeedsAnElementFactory(Func<IHtml,IElement> elementFactory)
{
CreateElement = elementFactory;
}
public void MethodUsingElementFactory()
{
IHtml domInstance = GetTheDOM();
var element = CreateElement(domInstance);
//the next line won't compile;
//the factory method is strongly typed to IHtml
var element2 = CreateElement("foo");
}
}
如果您想将代码保存在ElementFactory中而不是将其放在Autofac模块中,您可以将工厂方法设置为静态并注册(这在您的情况下特别有效,因为您的工厂方法通常是静态的): / p>
public class ElementFactory
{
public static IElement Create(IHtml dom)
{
switch (dom.ElementType)
{
case "table":
return new TableElement(dom);
case "div":
return new DivElement(dom);
case "span":
return new SpanElement(dom);
}
return new PassthroughElement(dom);
}
}
...
builder.Register<Func<IHtml, IElement>>(ElementFactory.Create);