Зачем нам нужен абстрактный шаблон дизайна фабрики?

Большая часть определения гласит:

Абстрактная фабрика предоставляет интерфейс для создания семейств связанных объектов без указания их конкретных классов.

Что такое абстрактный шаблон фабрики, поскольку мы можем решить задачу, создав объект самого конкретного класса. Почему у нас есть фабричный метод, который создает объект класса Concrete?

Пожалуйста, предоставьте мне какой-нибудь реальный пример из жизни, где я должен реализовать шаблон abstractFactory?

16 ответов

Abstract Factory - это центральный шаблон проектирования для Dependency Injection (DI). Вот список вопросов о переполнении стека, где в качестве решения было принято приложение Abstract Factory.

Насколько я понимаю, эти вопросы представляют собой реальные проблемы или проблемы, с которыми сталкивались люди, поэтому вам следует начать с некоторых реальных примеров:

Реальный пример использования шаблона Abstract Factory - предоставление доступа к данным двум различным источникам данных (например, базе данных SQL и файлу XML). У вас есть два разных класса доступа к данным (шлюз к хранилищу данных). Оба наследуют от базового класса, который определяет общие методы, которые будут реализованы (например, Load, Save, Delete).

Какой источник данных должен использоваться, не должен изменять способ получения клиентским кодом своего класса доступа к данным. Ваша абстрактная фабрика знает, какой источник данных должен использоваться, и возвращает соответствующий экземпляр по запросу. Фабрика возвращает этот экземпляр как тип базового класса.

Если я вас правильно понимаю - вопрос в том, почему у нас есть и метод Factory, и абстрактные шаблоны фабрики. Вам нужна абстрактная фабрика, когда разные полиморфные классы имеют разную процедуру создания экземпляров. И вы хотите, чтобы какой-то модуль создавал экземпляры и использовал их, не зная деталей инициализации объекта. Например - вы хотите создавать объекты Java, выполняя некоторые вычисления. Но некоторые из них являются частью приложения, в то время как байт-код другого должен считываться из БД. С другой стороны - зачем нам заводской метод? Согласитесь, эта абстрактная фабрика перекрывает это. Но в некоторых случаях - гораздо меньше кода для написания, меньше классов и интерфейсов облегчает понимание системы.

Что такое абстрактный шаблон фабрики, поскольку мы можем решить задачу, создав объект самого конкретного класса. Почему у нас есть фабричный метод, который создает объект класса Concrete?

При отсутствии абстрактной фабрики клиент должен знать детали конкретных классов. Эта жесткая связь была удалена с помощью Abstract Factory.

Теперь Factory Method выставляет контракт, который должен использовать клиент. Вы можете добавить больше продуктов на свою фабрику, добавив новые продукты, которые реализуют интерфейс, предоставляемый Factory Method.

Обратитесь к этим связанным вопросам SE для лучшего понимания:

В чем принципиальная разница между фабричными и абстрактными фабричными моделями?

Намерение:

Предоставить интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов.

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

Контрольный список:

  1. Решите, являются ли независимость платформы и сервисы создания в настоящее время источником боли.
  2. Составьте карту платформ и продуктов.
  3. Определите фабричный интерфейс, который состоит из фабричного метода для каждого продукта.
  4. Определите производный класс фабрики для каждой платформы, которая инкапсулирует все ссылки на новый оператор.
  5. Клиент должен удалить все ссылки на новые и использовать фабричные методы для создания объектов продукта.

Абстрактные фабрики отлично подходят для поддержки нескольких платформ, сохраняя при этом унифицированную кодовую базу. Предположим, у вас есть большая программа на Qt или GTK+ или.NET/Mono, которую вы хотите запустить в Windows, Linux и OSX. Но у вас есть функция, которая реализуется по-разному на каждой платформе (возможно, с помощью API-интерфейса kernel32 или POSIX).

public abstract class Feature
{
    public abstract int PlatformSpecificValue { get; }

    public static Feature PlatformFeature
    {
        get
        {
            string platform;
            // do platform detection here
            if (platform == "Win32")
                return new Win32Feature();
            if (platform == "POSIX")
                return new POSIXFeature();
        }
    }

    // platform overrides omitted
}

Благодаря этой абстрактной фабрике вашему интерфейсу не нужно ничего знать о текущей платформе.

Feature feature = Feature.PlatformFeature;
Console.WriteLine(feature.PlatformSpecificValue);

Это просто, представляя, что у вас есть код, который работает с абстракцией, вы должны создавать абстракции, а не конкретные классы.

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

Это хороший пример: http://en.wikipedia.org/wiki/Abstract_factory_pattern

Абстрактная фабрика или любая фабрика в этом отношении, они существуют для решения одной и той же проблемы, то есть "Абстракции создания объекта".

Обычно он абстрагирует следующее:

  1. if условие, чтобы решить, какой объект создать.
  2. new оператор, создание объекта.

Кратко об ответственности фабрики.

Вы можете просмотреть это для получения подробного объяснения.

Пример из реальной жизни представлен в пространстве имен System.Data.Common, которое имеет абстрактные базовые классы, которые включают DbConnection, DbCommand и DbDataAdapter и используются поставщиками данных.NET Framework, такими как System.Data.SqlClient и System.Data.OracleClient, которые позволяют разработчику писать общий код доступа к данным, который не зависит от конкретного поставщика данных.

Класс DbProviderFactories предоставляет статические методы для создания экземпляра DbProviderFactory. Затем экземпляр возвращает правильный строго типизированный объект на основе информации поставщика и строки подключения, предоставленной во время выполнения.

Пример:

 DataTable allProvidersTable = DbProviderFactories.GetFactoryClasses();

        /* Getting SqlClient family members */
        DbProviderFactory dbProviderFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
        DbCommand dbCommand = dbProviderFactory.CreateCommand();
        DbConnection dbConnection = dbProviderFactory.CreateConnection();
        DbDataAdapter dbDataAdapter = dbProviderFactory.CreateDataAdapter();

        SqlClientFactory sqlClientFactory = (SqlClientFactory)dbProviderFactory;
        SqlConnection sqlConnection = (SqlConnection)dbConnection;
        SqlCommand sqlCommand = (SqlCommand) dbCommand;
        SqlDataAdapter sqlDataAdapter = (SqlDataAdapter) dbDataAdapter;

        /* Getting OracleClient family members*/
        dbProviderFactory = DbProviderFactories.GetFactory("System.Data.OracleClient");
        dbCommand = dbProviderFactory.CreateCommand();
        dbConnection = dbProviderFactory.CreateConnection();
        dbDataAdapter = dbProviderFactory.CreateDataAdapter();

        OracleClientFactory oracleClientFactory = (OracleClientFactory)dbProviderFactory;
        OracleConnection oracleConnection = (OracleConnection)dbConnection;
        OracleCommand oracleCommand = (OracleCommand)dbCommand;
        OracleDataAdapter oracleDataAdapter = (OracleDataAdapter)dbDataAdapter;

Пример-2

Код Архитектура решения

Конкретные экземпляры Factory предоставляются с использованием статического метода Factory, как показано ниже.

public  class FurnitureProviderFactory
{
    public static IFurnitureFactory GetFactory(string furnitureType)
    {
        if (furnitureType == "Wood")
        {
            return new WoodenFurnitureFactory();
        }
        if (furnitureType == "Plastic")
        {
            return new PlasticFurnitureFactory();
        }
        throw new Exception("Undefined Furniture");
    }
}

Этот шаблон особенно полезен, когда клиент не знает точно, какой тип создать. В качестве примера, скажем, выставочный зал, продающий исключительно мобильные телефоны, получает запрос на смартфоны от Samsung. Здесь мы не знаем точный тип создаваемого объекта (при условии, что вся информация для телефона обернута в виде конкретного объекта). Но мы знаем, что ищем смартфоны производства Samsung. Эта информация действительно может быть использована, если в нашем проекте реализована абстрактная фабрика.

Понимание и реализация шаблона абстрактной фабрики в C#

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

Допустим, это бренд TYPE_A, а не один класс. Допустим, существует семейство из 100 подобных классов Type-A, и вам необходимо создать из них один объект. Представьте, что есть детальная, сложная информация, необходимая для того, чтобы сделать правильный объект из бренда многих похожих типов объектов, и в этом объектном объекте вы должны точно знать, какие параметры настраивать и как их настраивать.

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

И, возможно, завтра у нас будет другое семейство, скажем, type_B и type_C для создания экземпляра. Таким образом, пользовательский интерфейс будет "если еще" знать, хочет ли пользователь "type_A", "type_B" или "type_C" - но классы фабрик будут точно определять, какой класс из типа (из семейства) построить, и как его настроить - какие значения установить для его параметров или отправить его подрядчику. Все это - согласно многим параметрам, о которых пользовательский интерфейс не знает. Все это будет слишком много для одного фабричного класса.

Я считаю, что шаблон абстрактной фабрики переоценен.

Прежде всего, не часто бывает , что у вас есть набор взаимосвязанных типов, которые вы хотите создать.

Во-вторых, уровень косвенности (абстракции), предоставляемый интерфейсами, обычно достаточен при работе с внедрением зависимостей.

Типичный пример WindowsGui против MacGui против..., где у вас есть WindowsButton, MacButton, WindowsScrollBar, MacScrollbar и т. Д., Часто проще реализовать путем определения конкретных кнопок, полос прокрутки и т. Д. С использованием шаблона Visitor и / или Interpreter для предоставления фактическое поведение.

Чтобы ответить прямо на ваш вопрос, вы, вероятно, можете уйти, не используя такой шаблон проектирования.

Однако имейте в виду, что большинство проектов в реальном мире развиваются, и вы хотите обеспечить некоторую расширяемость, чтобы сделать ваш проект перспективным.

По моему опыту, в большинстве случаев реализуется Фабрика, и по мере роста проекта она превращается в более сложные шаблоны проектирования, такие как Абстрактная Фабрика.

Если вы посмотрите на шаблоны проектирования, почти все из них могут быть сокращены. Но какой шаблон означает широко используемый подход для решения проблем подобного типа. Шаблон проектирования предоставляет вам подход на уровне проектирования или решение ряда проблем проектирования аналогичного типа. Использование шаблона проектирования поможет вам решить вашу проблему и, следовательно, быстрее доставить.

Однажды я задал этот вопрос в компании, и, хотя это короткий ответ, он оказался верным и для меня.

Abstract Factory, так сказать, перемещает уровень абстракции на один уровень вверх, поэтому базовые реализации можно довольно легко заменить другой реализацией.

В нашем случае мы использовали Abstract Factory выше Hibernate, но мы могли бы заменить Hibernate на Toplink, iBatis или что-то еще, потому что абстрактная фабрика создает уровень абстракции выше кода Hibernate.

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

Скажем, вы создаете.jar, а кто-то еще использует ваш jar и хочет использовать новый конкретный объект в вашем коде. Если вы не используете абстрактную фабрику, она должна изменить ваш код или перезаписать ваш код. Но если вы используете абстрактную фабрику, то она может предоставить фабрику и перейти к вашему коду, и все в порядке.

Уточненная версия: рассмотрим нижеприведенный сценарий: кто-то еще написал фреймворк. Фреймворк использует абстрактную фабрику и некоторые конкретные фабрики для создания большого количества объектов во время выполнения. Таким образом, вы можете легко зарегистрировать свою собственную фабрику в существующей структуре и создавать свои собственные объекты. Фреймворк закрыт для модификаций и все еще легко расширяется из-за абстрактного фабричного шаблона.

Другие вопросы по тегам