Подтвердить что ты не робот

Абстрактный шаблон factory

  • Хороший пример для абстрактного шаблона factory в С#?
  • Каковы преимущества абстрактного шаблона factory в С#?
  • Как использовать генераторы С# с абстрактным шаблоном factory?
  • Как unit test с абстрактным шаблоном factory?
4b9b3361

Ответ 1

Прежде всего, я предлагаю вам прочитать о шаблоне Abstract Factory, например здесь. Теперь я попытаюсь объяснить, почему вы используете этот шаблон.

Обычно, если вы используете шаблон Factory, вы создадите объекты в Factory. Проблема возникает, когда у вас есть несколько реализаций данного класса (или классов). Теперь эти множественные реализации сгруппированы. Вы будете использовать Abstract Factory pattern, если у вас есть factory, но вы хотите сгруппировать создание объектов на группу.

Хорошо, выше объяснение может быть не совсем ясным, поэтому я приведу вам пример.

Скажем, у вас есть библиотека классов с агентами данных. Агент данных предоставляет вам способы доступа и хранения различных данных. Конечно, есть несколько способов хранения ваших данных. Например: в базе данных, в файле XML, над сервисом,. Для каждого из этих возможных способов вам нужны агенты данных. Теперь проблема в том, что вы не хотите, чтобы кто-то использовал DataAgentA для XML файлов вместе с DataAgentB для базы данных (предположим, что у нас есть сущности A и B). Пользователь должен использовать только один механизм хранения.

Позвольте представить вам образец Abstract Factory.

Вы убедитесь, что пользователи не могут напрямую создавать экземпляры ваших агентов данных, но им придется получить эти агенты данных из Factory. (Дополнительным преимуществом является то, что когда вы используете, например, базу данных (EF), вы можете выполнять внутреннюю проводку, чтобы убедиться, что ваши агенты данных используют один и тот же контекст и т.д.). Как это сделать? Мы устанавливаем конструктор наших агентов данных во "внутреннее". Кроме того, мы создаем разные фабрики для каждого механизма хранения. Теперь, поскольку все эти фабрики действуют одинаково, мы также имеем эти интерфейсы (как и наши агенты данных, поскольку все они должны делать то же самое, правильно!?).

Ниже мы имеем наши интерфейсы. В основном это шаблон Factory, но только теперь, а не о классах, мы говорим о интерфейсах.

public interface IAgentA 
{
    // Add some methods here!
}

public interface IAgentB
{
    // Add some methods here!
}

public interface IAgentFactory
{
    IAgentA CreateAgentA();
    IAgentB CreateAgentB();
}

Теперь для двух агентов у нас есть две возможные реализации: одна для XML и одна для хранения базы данных (опять же: это пример, вы можете иметь столько типов реализации, сколько хотите). Эти реализации будут выглядеть так (см. Ниже). Обратите внимание, что я создал конструктор internal! Это необходимо для части, которая приходит после этого блока кода.

public class AgentA_Xml : IAgentA
{
    internal AgentA_Xml()
    { /* Construction here */}

    // IAgentA method implementations
}

public class AgentB_Xml : IAgentB
{
    internal AgentB_Xml()
    { /* Construction here */}

    // IAgentB method implementations
}


public class AgentA_Database : IAgentA
{
    internal AgentA_Database()
    { /* Construction here */}

    // IAgentA method implementations
}

public class AgentB_Database : IAgentB
{
    internal AgentB_Database()
    { /* Construction here */}

    // IAgentB method implementations
}

Теперь, когда конструкторы являются внутренними. Это приводит к тому, что вы не можете создавать экземпляры этих классов вне сборки, что обычно происходит с такими случаями. Теперь мы должны создать наши заводы.

public class XMLAgentFactory : IAgentFactory
{
    public IAgentA CreateAgentA()
    {
        return new AgentA_Xml();
    }

    public IAgentB CreateAgentB()
    {
        return new AgentB_Xml();
    }
}


public class DatabaseAgentFactory : IAgentFactory
{
    public IAgentA CreateAgentA()
    {
        return new AgentA_Database();
    }

    public IAgentB CreateAgentB()
    {
        return new AgentB_Database();
    }
}

Поскольку обе фабрики реализуют интерфейс IAgentFactory, пользователь может легко изменить реализацию AgentFactory (если он в этом случае хочет использовать другой механизм хранения), не изменяя никакого другого кода, который он написал (против агенты), если он запрограммирован на интерфейсы (очевидно).

Наше объяснение, надеюсь, ответит на ваши вопросы (1) и (2).

  • Хороший пример для абстрактного шаблона Factory в С#?
  • и каковы преимущества абстрактного шаблона Factory в С#?

Отвечая на ваш вопрос (3).

  • Как использовать генераторы С# с абстрактным шаблоном Factory?

Вы все равно можете использовать generics, это не изменит ни одного бита при использовании абстрактного шаблона Factory. Конечно, вам придется создавать общие методы Factory (методы создания), но это не должно быть проблемой.

Отвечая на ваш вопрос (4).

  • Как unit test с абстрактным шаблоном Factory?

Точно так же, как и unit test любой другой класс. Только одно будет отличаться.

Поскольку вы, вероятно, также хотите протестировать конструктор своих классов (и, возможно, другие внутренние методы), вам нужно сделать внутренние конструкторы (методы) видимыми для вашего проекта unit test (и вы не хотите изменять internal до public). Это легко сделать, добавив следующую строку в ваш файл AssemblyInfo.cs вашего проекта (проект, в котором находится ваш Factory и классы):

[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("My.UnitTest.Namespace")]

Вы можете найти дополнительную информацию (и замечания) об атрибуте InternalsVisibleTo в MSDN.

Я надеюсь, что этот вопрос отвечает на ваш вопрос.