Задержка / Ленивое решение - PullRequest
1 голос
/ 04 октября 2011

С учетом следующего кода:

public interface IMyContext
{
    string subtype { get; set; }
}

public class MyContext : IMyContext
{
    public string subtype { get; set; }
}

public interface IMyExporter
{
    string Export();
}

public class MyExporterXML : IMyExporter
{
    public string Export()
    {
        return "";
    }
}

public class MyExporterJson : IMyExporter
{
    public string Export()
    {
        return "";
    }
}

public class MyExporterFactory
{
    private IMyContext context;
    public MyExporterFactory(IMyContext context)
    {
        this.context = context;
    }

    public IMyExporter Create()
    {
        switch (context.subtype)
        {
            case "JSON" :
                    return new MyExporterJson();
            default:
                    return new MyExporterXML();
        }
    }
}

public class MyService
{
    private IMyContext context;
    private IMyExporter exporter;
    public MyService(IMyContext context, IMyExporter exporter)
    {
        this.context = context;
        this.exporter = exporter;
    }

    public string Extractdata()
    {
        return exporter.Export();
    }
}

[TestClass]
public class UnitTest2
{
    [TestMethod]
    public void TestMethod1()
    {
        var container = new WindsorContainer();
        container.Register(Component.For<IMyContext>().ImplementedBy<MyContext>());
        container.Register(Component.For<MyExporterFactory>());
        container.Register(Component.For<MyService>());
        container.Register(Component.For<IMyExporter>().UsingFactoryMethod(kernel => kernel.Resolve<MyExporterFactory>().Create()));
        var context = container.Resolve<IMyContext>();
        var service = container.Resolve<MyService>();

        context.subtype = "JSON";

        service.Extractdata();

    }
}

Есть ли способ разрешить добавленный экспортер в MyService во время его фактического использования? То есть. при запуске приведенного выше кода разрешается экспортер MyExporterXML, но я действительно хочу, чтобы это был MyExporterJson из-за значения context.subtype = "JSON". Однако экспортер разрешается до того, как установлен подтип ...

Я знаю, что в Castle :: Windsor есть нечто, называемое фабриками на основе делегатов, но я просто не могу понять, как его использовать ....

Любая помощь будет принята с благодарностью, TIA

Сорен

1 Ответ

3 голосов
/ 07 октября 2011

Используйте комбинацию TypeFactoryFacility и пользовательского ITypedFactoryComponentSelector. Вот то, что должно работать в вашем случае.

Сначала создайте интерфейс для фабрики:

public interface IMyExporterFactory
{
    IMyExporter GetExporter(IMyContext context);
}

Далее, используйте настраиваемый фабричный селектор компонентов, который будет использовать подтип контекста, чтобы определить имя компонента (и изменить регистрацию для именования ваших экспортеров):

public class ExporterComponentSelector : DefaultTypedFactoryComponentSelector
{
    protected override string GetComponentName(MethodInfo method, object[] arguments)
    {
        if (method.Name == "GetExporter")
        {
            var context = (IMyContext) arguments[0];
            return context.subtype;
        }

        return base.GetComponentName(method, arguments);
    }
}

Вот обновление вашего регистрационного кода Windsor, которое включает TypedFactoryFacility и пользовательский селектор (и он называет ваших экспортеров на основе их подтипа):

var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(
    Component.For<IMyExporterFactory>().AsFactory(c => c.SelectedWith(new ExporterComponentSelector())),
    Component.For<IMyExporter>().ImplementedBy<MyExporterJson>().Named("json"),
    Component.For<IMyExporter>().ImplementedBy<MyExporterXML>().Named("xml"),
    Component.For<IMyContext>().ImplementedBy<MyContext>(),
    Component.For<MyService>()
    );

Теперь ваш сервис просто получает IMyExporterFactory и использует его для разрешения экспортера:

public class MyService
{
    private readonly IMyContext context;
    private readonly IMyExporterFactory exporterFactory;

    public MyService(IMyContext context, IMyExporterFactory exporterFactory)
    {
        this.context = context;
        this.exporterFactory = exporterFactory;
    }

    public string Extractdata()
    {
        var exporter = exporterFactory.GetExporter(context);
        return exporter.Export();
    }
}

Возможно, вы захотите убедиться, что если компоненты зарегистрированы с именами в нижнем регистре ("xml", "json"), чтобы ваш код всегда использовал имена в нижнем регистре (или использовал context.subtype.ToLower () в вашем ExporterComponentSelector).

...