Зачем нам нужен шаблон проектирования Абстрактная фабрика?

124

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

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

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

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

Amit
источник

Ответы:

218

Абстрактная фабрика - это центральный шаблон проектирования для внедрения зависимостей (DI). Вот список вопросов о переполнении стека, решение которых было принято с помощью Abstract Factory .

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

Марк Земанн
источник
6
Все эти примеры описывают шаблон фабричного метода, поскольку все они возвращают единый интерфейс продукта. Ни один из них не является шаблоном абстрактной фабрики, потому что ни один из них не создает семейства связанных интерфейсов продуктов.
jaco0646
32
В интересах полного раскрытия информации автор этого ответа должен был пояснить, что он также является автором каждого из связанных ответов; так что этот список НЕ является репрезентативной выборкой из сообщества SO.
jaco0646
1
@ jaco0646 IIRC, шаблон фабричного метода - это специализация шаблона метода шаблона , который основан на наследовании. Однако я могу ошибаться, так как в настоящее время путешествую, и у меня нет с собой книги GoF. Что вы имеете в виду под «ни один из них не производит семейства связанных интерфейсов продуктов»?
Mark Seemann
1
Самый простой способ указать, что фабрика не соответствует шаблону абстрактной фабрики, - это подсчитать абстрактные продукты, производимые фабрикой (я использовал термин «интерфейсы продуктов» вместо «абстрактные продукты», чтобы избежать чрезмерного использования слова «абстрактные»). , Фабрика, производящая один абстрактный продукт, не может быть абстрактной фабрикой, потому что абстрактная фабрика по определению производит семейство связанных продуктов . Важно отметить, что это семейство относится не к разным реализациям одного интерфейса, а к продуктам с разными связанными интерфейсами.
jaco0646
1
Вот пример oodesign.com/abstract-factory-pattern.html . Это то, для чего изначально был создан паттерн абстрактная фабрика.
user2802557
23

Реальный пример использования шаблона «Абстрактная фабрика» - это предоставление доступа к двум разным источникам данных. Предположим, ваше приложение поддерживает разные хранилища данных. (например, база данных SQL и файл XML). У вас есть два разных интерфейса доступа к данным, например, IReadableStoreи, IWritableStoreопределяющие общие методы, ожидаемые вашим приложением, независимо от типа используемого источника данных.

Какой тип источника данных следует использовать, не должен влиять на способ извлечения клиентским кодом классов доступа к данным. Вы AbstractDataAccessFactoryзнаете, какой тип источника данных настроен и предоставляет конкретную фабрику для клиентского кода, т . Е. SqlDataAccessFactoryИли XmlDataAccessFactory. Эти конкретные фабрики могут создавать конкретные реализации, например, SqlReadableStoreи SqlWriteableStore.

DbProviderFactory в .NET Framework является примером этого шаблона.

Йоханнес Рудольф
источник
18
Этот ответ может точно описывать шаблон Factory Method или шаблон Static Factory, но не шаблон Abstract Factory.
jaco0646
5

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

Давид Грузман
источник
4

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

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

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

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

В чем основное различие между шаблонами Factory и Abstract Factory?

Намерение:

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

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

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

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

Абстрактные фабрики отлично подходят для поддержки нескольких платформ, сохраняя при этом унифицированный код. Предположим, у вас есть большая программа 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);
piedar
источник
1
Я не понимаю, чем это отличается от простого использования фабричных методов для возврата абстрактного типа, чтобы клиент не знал деталей реализации?
kiwicomb123
1

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

Kangkan
источник
1

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

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

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

Пабло Кастилья
источник
1

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

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

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

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

eljenso
источник
У этого есть конкретная цель. с внедрением зависимостей вы не хотите, чтобы локаторы служб располагались дальше от составного корня. вместо этого вы используете внедренную абстрактную фабрику.
Адам Тюлипер - MSFT
2
ну ... использование локатора сервисов с DI - это антипатия. Абстрактная фабрика - универсальное решение, когда нам нужно создать ЗАВИСИМОСТИ от значений времени выполнения.
TheMentor 05
1

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

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

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

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

Уди Решеф
источник
1

Пример из реальной жизни представлен в пространстве имен 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");
    }
}
Hemendr
источник
0

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

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

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

BlueTrin
источник
0

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

Даниил
источник
0

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

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

Адриан Лю
источник
0

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

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

Амир Шабани
источник