这是当前代码的样子:
public static class WidgetFactory
{
public static AbstractWidget CreateWidget(WidgetSpec spec)
{
if (spec.ModelNo == "FOO")
return new FooWidget(spec);
if (spec.ModelNo == "BAR")
return new BarWidget(spec);
if (spec.ModelNo == "BOO")
return new BooWidget(spec);
}
}
这是我使用DI的实现:
的app.config
<components>
<component id="FOO"
service="MyCo.App.AbstractWidget"
type="MyCo.App.FooWidget, MyApp"
lifestyle="transient" />
<component id="BAR"
service="MyCo.App.AbstractWidget"
type="MyCo.App.BarWidget, MyApp"
lifestyle="transient" />
....
</components>
代码
static class WidgetFactory
{
static IWindsorContainer _container =
new WindsorContainer(new XmlInterpreter(new ConfigResource("castle")));
public static AbstractWidget CreateWidget(WidgetSpec spec)
{
return _container.Resolve<AbstractWidget>(spec.ModelNo, new { widgetSpec = spec });
}
}
这是正确的做法吗?我在忽视/做错/误会是什么?我应该为抽象类创建接口并从工厂返回它们吗?
(我更倾向于坚持使用这个特定应用程序的XML配置)
编辑:
KrzysztofKoźmic的建议:
public interface IFactory
{
AbstractFactory CreateWidget(WidgetSpec widgetSpec);
void ReleaseWidget(AbstractFactory widget);
}
public class CustomTypedFactoryComponentSelector : DefaultTypedFactoryComponentSelector
{
protected override string GetComponentName(MethodInfo method, object[] arguments)
{
WidgetSpec widgetSpec = arguments[0] as WidgetSpec;
if (method.Name == "CreateWidget" && arguments.Length == 1 && widgetSpec != null)
{
// The component mappings are stored as config settings
// for the sake of example
var componentName = Properties
.Settings
.Default
.Properties[widgetSpec.ModelNo]
.DefaultValue.ToString();
return componentName;
}
return base.GetComponentName(method, arguments);
}
}
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IFactory>().AsFactory(c => c.SelectedWith(new CustomTypedFactoryComponentSelector())));
//...
var factory = container.Resolve<IFactory>();
var widgetFactory = factory.CreateWidget(widgetSpec);
答案 0 :(得分:2)
您可以将Typed Factory与自定义选择器一起使用(有关示例和文档,请参阅this post)。
答案 1 :(得分:2)
在SO上回答有关依赖注入的问题时,我几乎总是说:“使用工厂”。我认为你的解决方案看起来很不错; - )
但也许还有一些改进空间。
因为工厂是静态类型,所以你别无选择,直接从代码中调用它。这使得很难测试该代码(如果可测试性当然是一个问题)。您可能尝试的是将工厂注入您正在使用的类型中的依赖项。因此,不要对静态类型进行硬依赖,而是在接口上创建依赖项。这看起来像这样:
public interface IWidgetFactory
{
AbstractWidget CreateWidget(WidgetSpec spec);
}
internal class WidgetFactory : IWidgetFactory
{
// code
}
现在您可以通过其界面轻松注册此类型:
<component
service="MyCo.App.IWidgetFactory, MyApp"
type="MyCo.App.WidgetFactory, MyApp"
lifestyle="singleton" />
现在你可以从容器中请求IWidgetFactory
,或者更好的是,在需要使用它的类型上注入IWidgetFactory
作为构造函数参数:
public class TypeUsingWidgets
{
private IWidgetFactory widgetFactory;
public TypeUsingWidgets(IWidgetFactory widgetFactory)
{
this.widgetFactory = widgetFactory;
}
public void MethodUsingWidgets()
{
var widget = this.factory.CreateWidget("Foo");
}
}
也许这对您的应用程序有益。