Урок 4. Паттерны проектирования. Абстрактная фабрика


Содержание материала:

Паттерн Abstract Factory (абстрактная фабрика)

Назначение паттерна Abstract Factory

Используйте паттерн Abstract Factory (абстрактная фабрика) если:

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

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

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

Другой пример. Рассмотрим текстовый редактор с многоязычной поддержкой, у которого имеются функциональные модули, отвечающие за расстановку переносов слов и проверку орфографии. Если, скажем, открыт документ на русском языке, то должны быть подключены соответствующие модули, учитывающие специфику русского языка. Ситуация, когда для такого документа одновременно используются модуль расстановки переносов для русского языка и модуль проверки орфографии для немецкого языка, исключается. Здесь группой взаимосвязанных объектов будут соответствующие модули, учитывающие специфику некоторого языка.

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

Описание паттерна Abstract Factory

Паттерн Abstract Factory реализуется на основе фабричных методов (см. паттерн Factory Method).

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

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

Для решения задачи по созданию семейств взаимосвязанных объектов паттерн Abstract Factory вводит понятие абстрактной фабрики. Абстрактная фабрика представляет собой некоторый полиморфный базовый класс, назначением которого является объявление интерфейсов фабричных методов, служащих для создания продуктов всех основных типов (один фабричный метод на каждый тип продукта). Производные от него классы, реализующие эти интерфейсы, предназначены для создания продуктов всех типов внутри семейства или группы. В случае нашей игры базовый класс абстрактной фабрики должен определять интерфейс фабричных методов для создания пехотинцев, лучников и конницы, а два производных от него класса будут реализовывать этот интерфейс, создавая воинов всех родов войск для той или иной армии.

UML-диаграмма классов паттерна Abstract Factory

Реализация паттерна Abstract Factory

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

Шаблон проектирования абстрактная фабрика на PHP

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

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

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

// Android
$andro >getPhone(«Android»);
$android->call();

// фабрика по производству телевизоров
$tvFactory = FactoryProducer::getFactory(«TVFactory»);

// SmartTV
$tv = $tvFactory->getTV(«SmartTV»);
print $tv->getBrand();

// SimpleTV
$tv = $tvFactory->getTV(«SimpleTV»);
print $tv->getBrand();
>
>

Таким образом, одна абстрактная фабрика порождает другие фабрики, которые уже непосредственно занимаются созданием конкретных объектов. При этом абстрактная фабрика в PHP просто содержит в себе набор абстрактных методов для создания объектов каждого типа.

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

Она выглядит вот так:

  • BB-код ссылки для форумов (например, можете поставить её в подписи):
  • Комментарии ( 0 ):

    Для добавления комментариев надо войти в систему.
    Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.

    Copyright © 2010-2020 Русаков Михаил Юрьевич. Все права защищены.

    Абстрактная фабрика

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

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

    Семейство зависимых продуктов. Скажем, Кресло + Диван + Столик .

    Несколько вариаций этого семейства. Например, продукты Кресло , Диван и Столик представлены в трёх разных стилях: Ар-деко , Викторианском и Модерне .

    Семейства продуктов и их вариации.

    Вам нужен такой способ создавать объекты продуктов, чтобы они сочетались с другими продуктами того же семейства. Это важно, так как клиенты расстраиваются, если получают несочетающуюся мебель.

    Клиенты расстраиваются, если получают несочетающиеся продукты.

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

    Для начала паттерн Абстрактная фабрика предлагает выделить общие интерфейсы для отдельных продуктов, составляющих семейства. Так, все вариации кресел получат общий интерфейс Кресло , все диваны реализуют интерфейс Диван и так далее.

    Все вариации одного и того же объекта должны жить в одной иерархии классов.

    Далее вы создаёте абстрактную фабрику — общий интерфейс, который содержит методы создания всех продуктов семейства (например, создатьКресло , создатьДиван и создатьСтолик ). Эти операции должны возвращать абстрактные типы продуктов, представленные интерфейсами, которые мы выделили ранее — Кресла , Диваны и Столики .

    Конкретные фабрики соответствуют определённой вариации семейства продуктов.

    Как насчёт вариаций продуктов? Для каждой вариации семейства продуктов мы должны создать свою собственную фабрику, реализовав абстрактный интерфейс. Фабрики создают продукты одной вариации. Например, ФабрикаМодерн будет возвращать только КреслаМодерн , ДиваныМодерн и СтоликиМодерн .

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

    Для клиентского кода должно быть безразлично, с какой фабрикой работать.

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

    Осталось прояснить последний момент: кто создаёт объекты конкретных фабрик, если клиентский код работает только с интерфейсами фабрик? Обычно программа создаёт конкретный объект фабрики при запуске, причём тип фабрики выбирается, исходя из параметров окружения или конфигурации.

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

    Конкретные продукты — большой набор классов, которые относятся к различным абстрактным продуктам (кресло/столик), но имеют одни и те же вариации (Викторианский/Модерн).

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

    Конкретные фабрики относятся каждая к своей вариации продуктов (Викторианский/Модерн) и реализуют методы абстрактной фабрики, позволяя создавать все продукты определённой вариации.

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

    В этом примере Абстрактная фабрика создаёт кросс-платформенные элементы интерфейса и следит за тем, чтобы они соответствовали выбранной операционной системе.

    Пример кросс-платформенного графического интерфейса пользователя.

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

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

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

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

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

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

    Абстрактная фабрика скрывает от клиентского кода подробности того, как и какие конкретно объекты будут созданы. Но при этом клиентский код может работать со всеми типами создаваемых продуктов, поскольку их общий интерфейс был заранее определён.

    Топ-пост этого месяца:  Темы для WordPress — из каких шаблонов они состоят и как все это работает

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

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

    Создайте таблицу соотношений типов продуктов к вариациям семейств продуктов.

    Сведите все вариации продуктов к общим интерфейсам.

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

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

    Измените код инициализации программы так, чтобы она создавала определённую фабрику и передавала её в клиентский код.

    Замените в клиентском коде участки создания продуктов через конструктор вызовами соответствующих методов фабрики.


      Гарантирует сочетаемость создаваемых продуктов. Избавляет клиентский код от привязки к конкретным классам продуктов. Выделяет код производства продуктов в одно место, упрощая поддержку кода. Упрощает добавление новых продуктов в программу. Реализует принцип открытости/закрытости.
      Усложняет код программы из-за введения множества дополнительных классов. Требует наличия всех типов продуктов в каждой вариации.

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

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

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

    Абстрактная фабрика может быть использована вместо Фасада для того, чтобы скрыть платформо-зависимые классы.

    Абстрактная фабрика может работать совместно с Мостом. Это особенно полезно, если у вас есть абстракции, которые могут работать только с некоторыми из реализаций. В этом случае фабрика будет определять типы создаваемых абстракций и реализаций.

    Порождающие шаблоны проектирования — Абстрактная фабрика

    Причины

    • Предоставление интерфейса для создания семейств связанных или зависимых объектов без указания их конкретных классов.
    • Иерархия, которая инкапсулирует: множество возможных «платформ» и построение набора «продуктов».
    • Оператор new считается вредным.

    Проблематика

    Если приложение должно быть портативным, ему необходимо инкапсулировать все зависимости целевой платформы. Эти «платформы» могут включать в себя: систему окон, операционную систему, базу данных и т. Д. Слишком часто эта инкапсуляция не разрабатывается заранее, и множество операторов case или различных #ifdef с параметрами для всех поддерживаемых в настоящее время платформ начинают размножаться подобно кроликам по всему коду.

    Обсуждение

    Обеспечние уровеня абстракции, который абстрагирует создание семейств связанных или зависимых объектов без прямого указания их конкретных классов. Объект «фабрика» несет ответственность за предоставление услуг по созданию всего семейства классов всех поддерживаемых платформ. Клиенты никогда не создают объекты платформы напрямую, они просят фабрику сделать это для них.

    Этот механизм упрощает изменение семейства порождаемых обхектов классов, поскольку конкретный класс фабричного объекта появляется только один раз в приложении — там, где он создается. Приложение может предосталвять возможности изменения всего семейства порождаемых объектов, просто создавая экземпляр другого конкретного экземпляра абстрактной фабрики.

    Поскольку сервис, предоставляемый фабричным объектом, настолько распространен, он обычно реализуется как Singleton. Либо он может реализоваться с помощью статических методов класса в случае с языком программирования C++.

    Структура

    Абстрактная фабрика определяет фабричный метод для каждого порождаемого объекта. Каждый фабричный метод инкапсулирует оператор new и конкретные, специфичные для платформы классы. Каждая «платформа» затем моделируется производным классом Factory.

    Пример

    Целью Абстрактной фабрики является предоставление интерфейса для создания семейств связанных объектов без указания конкретных классов. Эта модель может быть найдена в оборудовании для штамповки листового металла, используемом при изготовлении автомобилей. Оборудование для штамповки — это абстрактная фабрика, которая создает автозапчасти. Тот же механизм используется для штамповки дверей с правой стороны, левых дверей, правых передних крыльев, левых передних крыльев, вытяжек и т. д. для разных моделей автомобилей. Благодаря использованию роликов для изменения штамповочных шаблонов, конкретные классы, выпускаемые машиной, могут быть изменены в течение нескольких минут.

    Шаблоны проектирования простым языком. Часть первая. Порождающие шаблоны

    Шаблоны проектирования — это руководства по решению повторяющихся проблем. Это не классы, пакеты или библиотеки, которые можно было бы подключить к вашему приложению и сидеть в ожидании чуда. Они скорее являются методиками, как решать определенные проблемы в определенных ситуациях.

    Википедия описывает их следующим образом:

    Шаблон проектирования, или паттерн, в разработке программного обеспечения — повторяемая архитектурная конструкция, представляющая собой решение проблемы проектирования, в рамках некоторого часто возникающего контекста.

    Будьте осторожны

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

    Также заметьте, что примеры ниже написаны на PHP 7. Но это не должно вас останавливать, ведь принципы остаются такими же.

    Типы шаблонов

    Шаблоны бывают следующих трех видов:

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

    Порождающие шаблоны — шаблоны проектирования, которые абстрагируют процесс инстанцирования. Они позволяют сделать систему независимой от способа создания, композиции и представления объектов. Шаблон, порождающий классы, использует наследование, чтобы изменять наследуемый класс, а шаблон, порождающий объекты, делегирует инстанцирование другому объекту.

    Существуют следующие порождающие шаблоны:

    Простая фабрика (Simple Factory)

    В объектно-ориентированном программировании (ООП), фабрика — это объект для создания других объектов. Формально фабрика — это функция или метод, который возвращает объекты изменяющегося прототипа или класса из некоторого вызова метода, который считается «новым».

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

    Простыми словами: Простая фабрика генерирует экземпляр для клиента, не раскрывая никакой логики.

    Перейдем к коду. У нас есть интерфейс Door и его реализация:

    Затем у нас есть наша DoorFactory , которая делает дверь и возвращает её:

    И затем мы можем использовать всё это:

    Когда использовать: Когда создание объекта — это не просто несколько присвоений, а какая-то логика, тогда имеет смысл создать отдельную фабрику вместо повторения одного и того же кода повсюду.

    Фабричный метод (Fabric Method)

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

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

    Простыми словами: Менеджер предоставляет способ делегирования логики создания экземпляра дочерним классам.

    14 ноября в 18:30, Витебск, беcплатно

    Перейдём к коду. Рассмотрим приведенный выше пример про HR-менеджера. Изначально у нас есть интерфейс Interviewer и несколько реализаций для него:

    Теперь создадим нашего HiringManager :

    И теперь любой дочерний класс может расширять его и предоставлять необходимого интервьюера:

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

    Абстрактная фабрика (Abstract Factory)

    Абстрактная фабрика — порождающий шаблон проектирования, предоставляет интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов, не специфицируя их конкретных классов. Шаблон реализуется созданием абстрактного класса Factory, который представляет собой интерфейс для создания компонентов системы (например, для оконного интерфейса он может создавать окна и кнопки). Затем пишутся классы, реализующие этот интерфейс.

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

    Простыми словами: Фабрика фабрик. Фабрика, которая группирует индивидуальные, но связанные/зависимые фабрики без указания их конкретных классов.

    Обратимся к коду. Используем пример про двери. Сначала у нас есть интерфейс Door и несколько его реализаций:

    Затем у нас есть несколько DoorFittingExpert для каждого типа дверей:

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

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

    Когда использовать: Когда есть взаимосвязанные зависимости с не очень простой логикой создания.

    Строитель (Builder)

    Строитель — порождающий шаблон проектирования, который предоставляет способ создания составного объекта. Предназначен для решения проблемы антипаттерна «Телескопический конструктор».

    Пример из жизни: Представьте, что вы пришли в McDonalds и заказали конкретный продукт, например, БигМак, и вам готовят его без лишних вопросов. Это пример простой фабрики. Но есть случаи, когда логика создания может включать в себя больше шагов. Например, вы хотите индивидуальный сэндвич в Subway: у вас есть несколько вариантов того, как он будет сделан. Какой хлеб вы хотите? Какие соусы использовать? Какой сыр? В таких случаях на помощь приходит шаблон «Строитель».

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

    Давайте я покажу на примере, что такое «Телескопический конструктор». Когда-то мы все видели конструктор вроде такого:

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

    Перейдем к примеру в коде. Адекватной альтернативой будет использование шаблона «Строитель». Сначала у нас есть Burger , который мы хотим создать:

    Затем мы берём «Строителя»:

    Когда использовать: Когда может быть несколько видов объекта и надо избежать «телескопического конструктора». Главное отличие от «фабрики» — это то, что она используется, когда создание занимает один шаг, а «строитель» применяется при множестве шагов.


    Прототип (Prototype)

    Задаёт виды создаваемых объектов с помощью экземпляра-прототипа и создаёт новые объекты путём копирования этого прототипа. Он позволяет уйти от реализации и позволяет следовать принципу «программирование через интерфейсы». В качестве возвращающего типа указывается интерфейс / абстрактный класс на вершине иерархии, а классы-наследники могут подставить туда наследника, реализующего этот тип.

    Пример из жизни: Помните Долли? Овечка, которая была клонирована. Не будем углубляться, главное — это то, что здесь все вращается вокруг клонирования.

    Топ-пост этого месяца:  Установка Денвера

    Простыми словами: Прототип создает объект, основанный на существующем объекте при помощи клонирования.

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

    Обратимся к коду. В PHP это может быть легко реализовано с использованием clone :

    Затем он может быть клонирован следующим образом:

    Также вы можете использовать волшебный метод __clone для изменения клонирующего поведения.

    Когда использовать: Когда необходим объект, похожий на существующий объект, либо когда создание будет дороже клонирования.

    Одиночка (Singleton)

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

    Пример из жизни: В стране одновременно может быть только один президент. Один и тот же президент должен действовать, когда того требуют обстоятельства. Президент здесь является одиночкой.

    Простыми словами: Обеспечивает тот факт, что создаваемый объект является единственным объектом своего класса.

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

    Прим. перев. Подробнее о подводных камнях шаблона одиночка читайте в нашей статье.

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

    Задача паттерна Abstract Factory

    Чтобы просмотреть это видео, включите JavaScript и используйте веб-браузер, который поддерживает видео в формате HTML5

    ООП и паттерны проектирования в Python

    Half Faded Star

    Курс возводит слушателя от написания простых конкретных классов к профессиональному конструированию приложения в объектно-ориентированной парадигме. Паттерны проектирования позволяют шагнуть за пределы простого использования синтаксических конструкций языка. Вы научитесь писать красиво и элегантно, будете использовать проверенные временем концепции и создавать масштабируемые программы. Использование паттернов проектирования является признаком профессионализма программиста. Классические книги по паттернам проектирования описывают их реализацию на C++, C#, Java. У языка Python есть своя специфика из-за которой он отлично подходит для использования паттернов проектирования.

    Рецензии

    Half Faded Star

    В данной неделе Вы продолжите знакомство с паттернами проектирования. Мы разберём такие паттерны как Chain of Responsibility и Abstract Factory, после чего вы самостоятельно реализуете каждый из них. Закончим неделю изучением способа конфигурирования программ при помощи YAML.

    Преподаватели

    Максимов Егор Сергеевич

    Хирьянов Тимофей Фёдорович

    Герцев Михаил Николаевич

    Текст видео

    [БЕЗ_ЗВУКА] Теперь пора перейти к изучению поттерна Abstract Factory. Несмотря на то, что в большинстве литературы по шаблонам проектирования он стоит на первом месте, возможно, для понимания он один из наиболее сложных из-за присутствия элемента абстрактности. Дабы понять идею абстрактной фабрики, попрубуем рассмотреть пример из жизни. Вот представьте, что вы хотите построить дом. Перед тем, как есть строить, необходимо его спроектировать, написать чертежи. Зачастую сейчас при заказе проекта дома у компании они вам выдадут всю информацию, то есть дадут не только планировку, но и распишут, из какого материала строить, у какой окна, у какой люстры, а у какой выключатели, дабы они визуально соответствовали друг другу. Но все это не особо принципиально и зачастую может быть изменено уже после простройки каркаса. Ведь когда архитектор делает проект, он в первую очередь думает об удобстве тех, кто будет там жить, определяет, где будут располагаться двери, куда они будут открываться, какова должна быть высота потолка и где должны располагаться санузлы, а где окна. И уже в процессе строительства дома в зависимости от того, на какой фабрики вы закажете элементы, дом у вас будет либо с дубовыми окнами, дверьми и паркетом, или же с пластиковыми окнами, железными дверьми и ламинатом. В этом и есть суть абстрактной фабрики. На момент проектирования для нас абсолютно не важно знать, где мы возьмем все эти компоненты. Важно знать, что все эти компоненты мы сможем достать. Теперь о том, как это выглядит при программировании. Предположим, что нам нужна функция создания диалогового окна. Что для этого нам надо? Во-первых, надо уметь создавать окно. Во-вторых, надо уметь создавать кнопки. Например, «ОК», «Cancel» и прочее. И мы должны уметь выводить некоторую текстовую информацию, например, «А вы точно хотите удалить этот файл?». Может быть, необходимы какие-то дополнительные элементы, например, чекбоксы или радиобоксы и какие-нибудь прочие визуальные элементы. Так вот для функции создания диалога нет никакой необходимости знать, как создаются визуальный компоненты. Функции необходим лишь некий класс, который умеет все это делать, как фабрика- производить окна, кнопки и прочее. Что касается самих элементов, то их уже можно производить различным образом так, чтоб они выглядели либо в стиле операционной системы от Microsoft, Windows 90-х годов или Windows 10, или же в стиле OS X или Linux. Естественно, одна фабрика будет производить только кнопки одного типа, например, Windows 10. А уже другая фабрика будет производить кнопки в стиле OS X. Поэтому фабрика, с которой мы работаем во время написания функции диалогового окна, это некая абстрактная фабрика, в которой все необходимые функции только описаны, но не реализованы. Но когда из нашего приложения мы будем запускать функцию создания диалогового окна, мы ей будем передовать уже реальную фабрику, в которой все эти методы реализованы. В дальнейших видео мы займемся реализацией шаблонов реальной фабрики для формирования некоторого текстового отчета в различных форматах html и markdown. Причем сначала реализуем ее классическим способом, после чего произведем модификацию так, чтобы проект выглядел в духе Python’a, поскольку классическая реализация использует не все возможности данного языка и выглядит немножко чужой. Ну что ж, приступим к реализации! [ШУМ] [БЕЗ_ЗВУКА]

    ВИДЕОУРОК №7. Abstract Factory

    Доступ к полному курсу с учебными материалами и тестированием на 30 дней за 9.99 USD

    Метафора

    Описание метафоры (с диаграммой классов)

    Назначение паттерна

    Структура паттерна на языке UML

    Структура паттерна на языке C#

    Участники и мотивация

    Применимость паттерна

    Паттерн Abstract Factory

    Также известен как

    Kit (Набор инструментов)

    По цели: порождающий

    По применимости: к объектам

    Высокая — 1 2 3 4 5

    Паттерн AbstractFactory предоставляет клиенту интерфейс (набор методов) для создания семейств взаимосвязанных или взаимозависимых объектов-продуктов, при этом скрывает от клиента информацию о конкретных классах этих объектов-продуктов.

    Что такое фабрика в объективной реальности? Фабрика – это объект имеющий станки (методы), производящие продукты. Например, фабрика компании Coca-Cola производит сладкую газированную воду разлитую в жестяные банки. Предположим, что в помещении фабрики стоит два станка. Один станок размешивает и газирует сладкую воду, а другой станок формирует жестяные банки. После того как сладкая вода и жестяная банка произведены, требуется воду влить в банку, если сказать другими словами, то требуется организовать взаимодействие между двумя продуктами: водой и банкой. Опишем данный процесс с использованием диаграмм классов языка UML.

    На диаграмме видно, что фабрика Coca-Cola порождает два продукта: воду и банку. Эти продукты должны обязательно взаимодействовать друг с другом, иначе воду будет проблематично поставить потребителю, равно как и пустая банка потребителю не нужна. Порождаемые фабрикой Coca-Cola взаимосвязанные продукты (вода и банка) образуют семейство продуктов фабрики Coca-Cola.

    Фабрика компании Pepsi также порождает свое собственное семейство взаимодействующих и взаимозависимых продуктов (вода и банка).

    Важно заметить, что не логично пытаться наладить взаимодействие продуктов из разных семейств (например, вливать воду Coca-Cola в банку Pepsi или воду Pepsi в банку Coca-Cola). Скорее всего оба производителя будут против такого взаимодействия. Такой подход представляет собой пример антипатерна.

    Представим рассмотренные фабрики и порождаемые ими семейства продуктов в контексте одной программы.

    Сперва требуется создать абстрактные классы для задания типов продуктов ( AbstractWater и AbstractBottle ) и типа фабрик ( AbstractFactory ). Описать интерфейсы взаимодействия с каждым типом продукта и фабрики.

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

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

    См. пример к главе: \001_AbstractFactory\000_CocaCola_Pepsi

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

    Структура паттерна на языке UML

    См. пример к главе: \001_AbstractFactory\001_AbstractFactory

    Структура паттерна на языке C#

    • AbstractProduct — Абстрактный продукт:
    • AbstractFactory — Абстрактная фабрика:
    • Client — Клиент:
    • ConcreteProduct — Конкретный продукт:
    • ConcreteFactory — Конкретная фабрика:
    • Класс Client связан связями отношения ассоциации с классами абстрактных продуктов и классом абстрактной фабрики.
    • Все конкретные классы продуктов связаны связями отношения наследования с абстрактными классами продуктов.

    • Все конкретные классы фабрик связаны связями отношения наследования с классом абстрактной фабрики и связями отношения зависимости (стереотипа — instantiate) с конкретными классами порождаемых продуктов.
    • В системе создается (чаще всего) только один экземпляр конкретной фабрики. Задачей конкретной фабрики является создание объектов продуктов, входящих в определенное семейство.
    • При создании экземпляра клиента, клиент конфигурируется экземпляром конкретной фабрики (ссылка на экземпляр фабрики передается в качестве аргумента конструктора клиента).
    • Абстрактный класс AbstractFactory передает ответственность за создание объектов-продуктов производным конкретным фабрикам.

    Рассмотрим простейшую программу, в которой поддерживается возможность создания и использования нескольких стилей пользовательского интерфейса, например, стиль Windows Explorer и стиль Mac OS Snow Leopard. В программе будут использоваться два элемента пользовательского интерфейса («controls — контролы» или иногда используется устаревшее название «widgets — виджеты»): Форма и Кнопка.

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

    Создадим абстрактный класс WidgetFactory , в котором имеется интерфейс (набор абстрактных фабричных методов) для создания элементов управления. Создадим абстрактные классы AbstractWindow и AbstractButton для описания каждого отдельного вида элемента управления и конкретные подклассы ( WindowsForm , LeopardForm и WindowsButton , LeopardButton ), реализующие элементы управления с определенным стилем. В абстрактном классе WidgetFactory имеются абстрактные операции (CreateWindow и CreateButton), возвращающие ссылки на новые экземпляры элементов управления для каждого абстрактного типа контролов. Клиент вызывает эти операции для получения экземпляров контролов, но при этом ничего не знает о том, какие именно конкретные классы используются для их построения. Соответственно клиент ничего не знает и о реализации выбранного стиля.

    Для порождения контролов определенного стиля используются классы WindowsFactory и LeopardFactory производные от базового класса WidgetFactory , которые реализуют операции, необходимые для создания элемента управления определенного стиля. Например, операция CreateButton в классе WindowsFactory создает и возвращает кнопку в стиле Windows, тогда как операция CreateButton в классе LeopardFactory возвращает кнопку в стиле Snow Leopard. Клиент ( Client ) создает элементы управления, пользуясь исключительно интерфейсом, заданным в абстрактном классе WidgetFactory , и ему ничего не известно о классах, реализующих контролы для каждого конкретного стиля. Другими словами, клиент должен лишь придерживаться интерфейса, определенного абстрактным классом, а не конкретным классом.

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

    Рисунок. Результат подмены фабрик.

    См. пример к главе: \001_AbstractFactory\002_WidgetFactory

    Паттерн Abstract Factory рекомендуется использовать, когда:

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

    Паттерн Abstract Factory обладает следующими преимуществами:

    • Сокрытие работы с конкретными классами продуктов.

    Фабрика скрывает от клиента детали реализации конкретных классов и процесс создания экземпляров этих классов. Конкретные классы-продуктов известны только конкретным фабрикам и в коде клиента они не используются. Клиент управляет экземплярами конкретных классов только через их абстрактные интерфейсы.

    • Позволяет легко заменять семейства используемых продуктов.

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

    • Обеспечение совместного использования продуктов.

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

    Паттерн Abstract Factory обладает следующим недостатком:

    • Имеется небольшое неудобство добавления нового вида продуктов.

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

    Полезные приемы реализации паттерна Abstract Factory:

    • Объекты-фабрики существуют в единственном экземпляре.

    В подсистеме, создается только один экземпляр класса ConcreteFactory для порождения, соответствующего семейства продуктов.

    • Создание объектов-продуктов.

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

    • Определение расширяемых фабрик.

    Класс AbstractFactory содержит абстрактные операции для создания продуктов. Имена фабричных методов включают в себя название типа порождаемого продукта. Для добавления нового вида продуктов нужно добавить новый абстрактный фабричный метод в абстрактный класс AbstractFactory и реализовать этот метод в производных классах-фабриках.

    Более гибкий способ – использовать фабричные методы с аргументами, описывающими виды создаваемых продуктов. Тип аргумента может быть числовой, строковой или типом перечисления ( enum ), однозначно описывающий тип порождаемого продукта. При таком подходе абстрактному классу AbstractFactory нужна только одна операция Make с аргументом, указывающим тип создаваемого продукта.

    Интересные и гибкие варианты порождения можно организовать в динамически типизированных языках, каким и является C#. Языки с поддержкой динамической типизации позволяют создавать семейства продуктов без наличия общего абстрактного базового класса, а фабричные методы могут иметь возвращаемые значения динамического типа ( dynamic ). Также в языке C# абстрактный класс можно заменить конструкцией языка выражающей такой стереотип как «интерфейс» ( interface IAbstractFactory ).
    Если в клиенте отказаться от приведения продуктов к базовому абстрактному типу то, можно было бы выполнить динамическое приведение типа (например, с помощью оператора dynamic в C#), но это не всегда безопасно и не всегда заканчивается успешно. Может возникнуть проблемная ситуация: все продукты будут возвращаться клиенту с интерфейсом, который не отображается в intellisense (intellisense – технология автодополнения), клиенту будет сложно различать динамические типы продуктов, и могут возникать сложности с их использованием. Такие варианты представляют собой пример компромисса между гибкостью, расширяемостью интерфейса и производительностью.

    См. пример к главе: \001_AbstractFactory\003_AbstractFactory_Net

    Пример кода игры «Лабиринт»

    Реализацию игры-лабиринта, которая рассматривалась в начале этой главы можно изменить так, чтобы показать на ее примере возможность использования паттерна Abstract Factory .
    Класс MazeFactory будет использоваться для создания компонентов лабиринта (комнат, стен и дверей между комнатами).

    Метод CreateMaze класса MazeGame , принимает аргумент типа MazeFactory и возвращает построенный лабиринт (ссылку на экземпляр класса Maze ).

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

    Класс-фабрика EnchantedMazeFactory переопределяет фабричные методы базового класса-фабрики MazeFactory .

    Предположим, что в данном лабиринте в одной из комнат заложена бомба, когда бомба взрывается то в комнате обрушиваются стены. Для этого нужно создать классы BombedWall и RoomWithABomb . Класс BoombedWall наследуется от класса Wall , а класс RoomWithABomb наследуется от класса Room .

    Класс фабрика BombedMazeFactory переопределяет фабричные методы базового класса фабрики MazeFactory

    Для построения лабиринта с бомбами вызывается метод CreateMaze класса MazeGame , которому в качестве аргумента передаётся ссылка на экземпляр класса BombedMazeFactory .

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

    См. пример к главе: \MAZE\001_Maze_AF

    Паттерн Abstract Factory в java — Абстрактная Фабрика

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

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

    Перед тем, как привести пример использования Фабрики на Java, рассмотрим небольшую диаграмму классов (с Paint я творю чудеса :)):

    Из диаграммы видно, что клент после ипользования Фабрики для создания объектов, манипулирует объектами на более высоком уровне абстракции.

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

    Интерфейсы персонажей будут следующие:

    Перейдем к конкретным классам:

    Аналогичные классы можно создать для других рас.

    Ну а теперь перейдем к использованию выше описанных классов для создания отряда. Функция создания отрядов будет иметь следующий вид:

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

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

    Используйте паттерн Абстрактная Фабрика в таких случаях:

    • система не должна зависеть от способа создания объектов;
    • система работает с одним из нескольких семейств объектов;
    • объекты внутри семейства взаимосвязаны.

    Комментарии по поводу статьи приветствуются.

    Шаблоны проектирования: Простая Фабрика

    Что вам приходит в голову, когда вы слышите слово “фабрика”? Для меня это место производства каких-то вещей — это действительно так. Стоит добавить, что произведённая продукция зависит от заказа.

    К примеру вы заказали себе машину. Фабрика сконструирует её согласно внутренним правилам и спецификациям.

    По аналогии, в мире программирования шаблон проектирования фабрика используется для создания объектов по заданным параметрам.

    1. Простая Фабрика. Позволяет создавать объекты без логики их создания в клиенте.
    2. Фабричный метод. Позволяет подклассам определять какой класс инициализировать.
    3. Абстрактная фабрика. В отличии от предыдущих методов, абстрактная фабрика позволяет создавать связные объекты.

    Проблема

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

    Со временем в процессе создания объекта Car нужно будет вводить некоторые изменения. К примеру создавать объект автомобиля нужно согласно определённым типам. Таким образом нам нужно будет менять код везде, где до тех пор создавался объект класса Car.

    Через некоторое время ситуация может измениться ещё раз и ещё раз.

    Чтобы не менять код проекта раз за разом целесообразно создать отдельный класс по шаблону Фабрика.

    Решение

    Теперь давайте создадим функционал по которому объект автомобиля будет создаваться по ключевому слову. Далее это позволит нам без проблем создавать автомобили по их типу: Sedan, SUV и так далее.

    Реализуем шаблон проектирования Простая Фабрика. Обратите внимание на фабричный метод build.

    Итак, у нас есть один абстрактный метод, который создаёт объекты других классов согласно типу автомобиля. Теперь нам необходимо создать классы самих автомобилей:

    Теперь можем создавать автомобили:

    Добавляем новый класс

    Теперь добавить новый тип автомобиля проще простого. Пример:

    Вывод

    Шаблон проектирования Простая Фабрика позволяет нам создать централизованное место создания объектов схожего типа.

    Данный урок подготовлен для вас командой сайта ruseller.com
    Источник урока: http://code.tutsplus.com/tutorials/design-patterns-the-simple-factory-pattern—cms-22345
    Перевел: Станислав Протасевич
    Урок создан: 26 Апреля 2015
    Просмотров: 7783
    Правила перепечатки

    5 последних уроков рубрики «PHP»

    Фильтрация данных с помощью zend-filter

    Когда речь идёт о безопасности веб-сайта, то фраза «фильтруйте всё, экранируйте всё» всегда будет актуальна. Сегодня поговорим о фильтрации данных.

    Контекстное экранирование с помощью zend-escaper

    Обеспечение безопасности веб-сайта — это не только защита от SQL инъекций, но и протекция от межсайтового скриптинга (XSS), межсайтовой подделки запросов (CSRF) и от других видов атак. В частности, вам нужно очень осторожно подходить к формированию HTML, CSS и JavaScript кода.

    Подключение Zend модулей к Expressive

    Expressive 2 поддерживает возможность подключения других ZF компонент по специальной схеме. Не всем нравится данное решение. В этой статье мы расскажем как улучшили процесс подключение нескольких модулей.

    Совет: отправка информации в Google Analytics через API

    Предположим, что вам необходимо отправить какую-то информацию в Google Analytics из серверного скрипта. Как это сделать. Ответ в этой заметке.

    Подборка PHP песочниц

    Подборка из нескольких видов PHP песочниц. На некоторых вы в режиме online сможете потестить свой код, но есть так же решения, которые можно внедрить на свой сайт.

    Порождающие паттерны: Абстрактная фабрика (Abstract factory)

    Назначение: абстрактная фабрика предоставляет интерфейс для создания семейства взаимосвязанных или родственных объектов (dependent or related objects), не специфицируя их конкретных классов.

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

    Когда следует использовать абстрактную фабрику

    Когда система не должна зависеть от способа создания новых объектов

    Когда создаваемые объекты должны использоваться вместе и являются взаимосвязанными

    Топ-пост этого месяца:  Где скачать WordPress — только с официального сайта wordpress.org
    Добавить комментарий