Возможности использования абстрактных фабрик со StructureMap

public interface IExecuter
{
    void Execute();
}

public class Executer : IExecuter
{
    readonly Data _data;
    readonly IService _service;

    public Executer(Data data, IService service)
    {
        _data = data;
        _service = service;
    }

    public void Execute()
    {
        Console.WriteLine("I consume the data object with id {0}", _data.Id);
        _service.DoAnything();
    }
}

public interface IService
{
    void DoAnything();
}

public class Service : IService
{
    public void DoAnything()
    {
        Console.WriteLine("I do anything else");
    }
}

public class Data
{
    public int Id { get; set; }
    public string Description { get; set; }
}

Теперь мне нужна абстрактная фабрика для создания IExecuter, потому что мне нужно передать значение времени выполнения в конструктор.

Вариант №1 — используйте статическую абстрактную фабрику:

public class FormularWindow
{
    public static Func<Data, IExecuter> CreateExecuter = data => {throw new NotImplementedException("");};

    public void InvokeExecuter()
    {
        var selectedData = GetSelectedData();
        var executer = CreateExecuter (selectedData);
        executer.Execute();
    }

    private static Data GetSelectedData()
    {
        return new Data { Id = 4, Description = "Test" };
    }
}

class Program
{
    static void Main()
    {
        ObjectFactory.Initialize(x =>
        {
            x.For<IExecuter>().Use<Executer>();
            x.For<IService>().Use<Service>();
        });
        FormularWindow.CreateExecuter = data => ObjectFactory.With(data.GetType(), data).GetInstance<IExecuter>();

        var consumer = ObjectFactory.GetInstance<FormularWindow>();

        consumer.InvokeExecuter();

        Console.ReadLine();
    }
}

Вариант №2 – использовать абстрактную фабрику в качестве параметра конструктора:

public class FormularWindow
{
    readonly Func<Data, IExecuter> _createExecuter;

    public FormularWindow(Func<Data, IExecuter> createExecuter)
    {
        _createExecuter = createExecuter;
    }

    public void InvokeExecuter()
    {
        var selectedData = GetSelectedData();
        var executer = _createExecuter(selectedData);
        executer.Execute();
    }

    private static Data GetSelectedData()
    {
        return new Data { Id = 4, Description = "Test" };
    }
}

class Program
{
    static void Main()
    {
        ObjectFactory.Initialize(x =>
        {
            x.For<IExecuter>().Use<Executer>();
            x.For<IService>().Use<Service>();
            x.For<Func<Data, IExecuter>>().Use(data => ObjectFactory.With(data.GetType(), data).GetInstance<IExecuter>());
        });


        var consumer = ObjectFactory.GetInstance<FormularWindow>();

        consumer.InvokeExecuter();

        Console.ReadLine();
    }
}

Вариант №3 — Используйте IExecuterFactory:

class Program
{
    static void Main()
    {
        ObjectFactory.Initialize(x =>
        {
            x.For<IExecuter>().Use<Executer>();
            x.For<IService>().Use<Service>();
            x.For<IExecuterFactory>().Use<ExecuterFactory>();
        });

        var consumer = ObjectFactory.GetInstance<FormularWindow>();

        consumer.InvokeExecuter();

        Console.ReadLine();
    }
}

public interface IExecuterFactory
{
    IExecuter Create(Data data);
}

public class ExecuterFactory : IExecuterFactory
{
    readonly IService _service;

    public ExecuterFactory(IService service)
    {
        _service = service;
    }

    public IExecuter Create(Data data)
    {
        return new Executer(data, _service);// ?!
    }
}


public class FormularWindow
{
    readonly IExecuterFactory _executerFactory;


    public FormularWindow(IExecuterFactory executerFactory)
    {
        _executerFactory = executerFactory;
    }

    public void InvokeExecuter()
    {
        var selectedData = GetSelectedData();
        var executer = _executerFactory.Create(selectedData);
        executer.Execute();
    }

    private static Data GetSelectedData()
    {
        return new Data { Id = 4, Description = "Test" };
    }
}

С возможностью №3 я не знаю, как это реализовать, как видите. Я мог бы снова использовать Func в конструкторе ExecuterFactory, но это было бы странно, потому что я использую абстрактную фабрику внутри абстрактной фабрики.

Также была бы возможность #4 внедрить контейнер, но это было бы плохой идеей из-за введения локатора сервисов.

Я спрашиваю себя, есть ли способ использовать абстрактные фабрики без Func<>?


person Rookian    schedule 26.04.2012    source источник


Ответы (1)


Я бы не назвал это Abstract Factory, это похоже на функциональный эквивалент того, что некоторые называют Простая фабрика.

Я предлагаю вам взглянуть на публикацию Марка Симанна об абстрактных фабриках, он объясняет несколько вариантов в простой форме.

На практике вы можете вызвать свой контейнер в ExecuterFactory для решения своих зависимостей, если он находится в том же проекте, что и корень вашей композиции, или создать их экземпляр самостоятельно, new создав их в вашей фабрике, закодированной вручную. Я предпочитаю ручной подход, потому что мне нравится идея свести использование контейнера к минимуму.

person Filippo Pensalfini    schedule 26.04.2012
comment
Я отредактировал свой вопрос. Простая фабрика позволит создать конкретную реализацию. Тип возвращаемого значения абстрактной фабрики — это абстракция в форме интерфейса или абстрактного класса. В моем примере это так. - person Rookian; 26.04.2012
comment
@Rookian Извините, я не хотел начинать обсуждение определений Abstract Factory / Simple Factory в этом месте, так как это не главное. Тем не менее, похоже, вы поняли, о чем я говорил, и отредактировали свой ответ :) Удовлетворяет ли он вашим потребностям? - person Filippo Pensalfini; 26.04.2012
comment
Я не уверен, стоит ли обновлять Executer. - person Rookian; 26.04.2012
comment
@Rookian хорошо, вы должны как-то создать его экземпляр во время выполнения, я не вижу ничего плохого в создании чего-то вручную на фабрике, в конце концов, это его роль в качестве шаблона. Что тебе в нем не нравится? - person Filippo Pensalfini; 27.04.2012