Dependency injection I';我想使用依赖注入(Castle Windsor)来替换一些工厂代码I';我继承了。我是否采取了正确的方法?

Dependency injection I';我想使用依赖注入(Castle Windsor)来替换一些工厂代码I';我继承了。我是否采取了正确的方法?,dependency-injection,castle-windsor,Dependency Injection,Castle Windsor,这是当前代码的外观: public static class WidgetFactory { public static AbstractWidget CreateWidget(WidgetSpec spec) { if (spec.ModelNo == "FOO") return new FooWidget(spec); if (spec.ModelNo == "BAR") return new Ba

这是当前代码的外观:

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>

....        
代码

静态类WidgetFactory
{
静态IWindsorContainer\u container=
新WindsorContainer(新XmlTransparer(新配置资源(“城堡”));
公共静态AbstractWidget CreateWidget(WidgetSpec规范)
{
返回_container.Resolve(spec.ModelNo,new{widgetSpec=spec});
}
}
这是正确的方法吗?我忽略了什么/做错了什么/误解了什么?我应该为抽象类创建接口并从工厂返回它们吗

(对于这个特定的应用程序,我更愿意使用XML配置)

编辑:

Krzysztof Koź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);
公共接口IFactory
{
AbstractFactory CreateWidget(WidgetSpec-WidgetSpec);
作废发布小部件(AbstractFactory小部件);
}
公共类CustomTypedFactoryComponentSelector:DefaultTypedFactoryComponentSelector
{
受保护的重写字符串GetComponentName(MethodInfo方法,对象[]参数)
{
WidgetSpec WidgetSpec=参数[0]作为WidgetSpec;
if(method.Name==“CreateWidget”&&arguments.Length==1&&widgetSpec!=null)
{
//组件映射存储为配置设置
//为了以身作则
var componentName=属性
.设置
违约
.Properties[widgetSpec.ModelNo]
.DefaultValue.ToString();
返回组件名称;
}
返回base.GetComponentName(方法、参数);
}
}
container.AddFacility();
container.Register(Component.For().AsFactory(c=>c.SelectedWith(新的CustomTypedFactoryComponentSelector()));
//...
var factory=container.Resolve();
var widgetFactory=factory.CreateWidget(widgetSpec);

您可以将类型化工厂与自定义选择器一起使用(请参阅示例和文档)。

您可以将类型化工厂与自定义选择器一起使用(请参阅示例和文档)。

在回答有关依赖项注入的问题时,我几乎总是说:“使用工厂”。我认为你的解决方案看起来不错;-)

不过,或许还有一些改进的空间

因为工厂是一个静态类型,所以除了直接从代码中调用它之外,您别无选择。这使得测试代码变得很困难(当然,如果可测试性是一个问题的话)。您可以尝试将工厂作为依赖项注入正在使用的类型中。因此,与其对静态类型具有硬依赖,不如在接口上创建依赖。这可能是这样的:

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" />

也许这对您的应用程序是有益的。

在回答关于依赖注入的问题时,我几乎总是说:“使用工厂”。我认为你的解决方案看起来不错;-)

不过,或许还有一些改进的空间

因为工厂是一个静态类型,所以除了直接从代码中调用它之外,您别无选择。这使得测试代码变得很困难(当然,如果可测试性是一个问题的话)。您可以尝试将工厂作为依赖项注入正在使用的类型中。因此,与其对静态类型具有硬依赖,不如在接口上创建依赖。这可能是这样的:

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" />

也许这对您的应用程序是有益的。

我遵循了这篇文章,提出了一些我认为与我的场景相关的代码。我做得对吗?我已经按照帖子写了一些我认为与我的场景相关的代码。我做得对吗?