Вы находитесь на странице: 1из 9

Фабричный метод

Фабричный метод — это порождающий паттерн проектирования, который определяет


общий интерфейс для создания объектов в суперклассе, позволяя подклассам изменять
тип создаваемых объектов.
Определяет интерфейс для создания объекта, но оставляет подклассам решение о том,
на основании какого класса создавать объект. Фабричный метод позволяет классу
делегировать создание подклассов. Используется, когда:
• классу заранее неизвестно, объекты каких подклассов ему нужно создавать.
• класс спроектирован так, чтобы объекты, которые он создаёт, специфицировались
подклассами.
• класс делегирует свои обязанности одному из нескольких вспомогательных
подклассов, и планируется локализовать знание о том, какой класс принимает эти
обязанности на себя.
Проблема
Представьте, что вы создаёте программу управления грузовыми перевозками. Сперва
вы рассчитываете перевозить товары только на автомобилях. Поэтому весь ваш код
работает с объектами класса Грузовик.
В какой-то момент ваша программа становится настолько известной, что морские
перевозчики выстраиваются в очередь и просят добавить поддержку морской логистики
в программу.
Отличные новости, правда?! Но как насчёт кода? Большая часть существующего кода
жёстко привязана к классам Грузовиков. Чтобы добавить в программу классы морских
Судов, понадобится перелопатить всю программу. Более того, если вы потом решите
добавить в программу ещё один вид транспорта, то всю эту работу придётся повторить.
В итоге вы получите ужасающий код, наполненный условными операторами, которые
выполняют то или иное действие, в зависимости от класса транспорта.
Решение
Паттерн Фабричный метод предлагает создавать объекты не напрямую, используя
оператор new, а через вызов особого фабричного метода. Не пугайтесь, объекты всё
равно будут создаваться при помощи new, но делать это будет фабричный метод.
На первый взгляд, это может показаться бессмысленным: мы просто переместили вызов
конструктора из одного конца программы в другой. Но теперь вы сможете
переопределить фабричный метод в подклассе, чтобы изменить тип создаваемого
продукта.
Чтобы эта система заработала, все возвращаемые объекты должны иметь общий
интерфейс. Подклассы смогут производить объекты различных классов, следующих
одному и тому же интерфейсу.
Например, классы Грузовик и Судно реализуют интерфейс Транспорт с методом
доставить. Каждый из этих классов реализует метод по-своему: грузовики везут грузы
по земле, а суда — по морю. Фабричный метод в классе ДорожнойЛогистики вернёт
объект-грузовик, а класс МорскойЛогистики — объект-судно.
Достоинства
• позволяет сделать код создания объектов более универсальным, не привязываясь к
конкретным классам (ConcreteProduct), а оперируя лишь общим интерфейсом (Product);
• позволяет установить связь между параллельными иерархиями классов.
Недостатки
• необходимость создавать наследника Creator для каждого нового типа продукта
(ConcreteProduct).
Абстрактная фабрика
Абстрактная фабрика — это порождающий паттерн проектирования, который
позволяет создавать семейства связанных объектов, не привязываясь к конкретным
классам создаваемых объектов.
Предоставляет интерфейс для создания семейств взаимосвязанных или
взаимозависимых объектов, не специфицируя их конкретных классов.

Плюсы

 изолирует конкретные классы;


 упрощает замену семейств продуктов;
 гарантирует сочетаемость продуктов.

Минусы

 сложно добавить поддержку нового вида продуктов.

Применение

 Система не должна зависеть от того, как создаются, компонуются и


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

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


1. Семейство зависимых продуктов. Скажем, Кресло + Диван + Столик.
2. Несколько вариаций этого семейства. Например, продукты Кресло, Диван и Столик
представлены в трёх разных стилях: Ар-деко, Викторианском и Модерне.
Клиентский код должен работать как с фабриками, так и с продуктами только через их
общие интерфейсы. Это позволит подавать в ваши классы любой тип фабрики и
производить любые продукты, ничего не ломая. Для клиентского кода должно быть
безразлично, с какой фабрикой работать.
Например, клиентский код просит фабрику сделать стул. Он не знает, какого типа была
эта фабрика. Он не знает, получит викторианский или модерновый стул. Для него
важно, чтобы на стуле можно было сидеть и чтобы этот стул отлично смотрелся с
диваном той же фабрики.
Осталось прояснить последний момент: кто создаёт объекты конкретных фабрик, если
клиентский код работает только с интерфейсами фабрик? Обычно программа создаёт
конкретный объект фабрики при запуске, причём тип фабрики выбирается, исходя из
параметров окружения или конфигурации.
Строитель
Строитель (англ. Builder) — порождающий шаблон проектирования предоставляет
способ создания составного объекта.

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

Плюсы

 позволяет изменять внутреннее представление продукта;


 изолирует код, реализующий конструирование и представление;
 дает более тонкий контроль над процессом конструирования.

Минусы

 алгоритм создания сложного объекта не должен зависеть от того, из каких частей


состоит объект и как они стыкуются между собой;
 процесс конструирования должен обеспечивать различные представления
конструируемого объекта.

Разные строители выполнят одну и ту же задачу по-разному.

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

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

Применение
Паттерн используется чтобы:

 избежать дополнительных усилий по созданию объекта стандартным путём


(имеется в виду использование конструктора, так как в этом случае также будут
вызваны конструкторы всей иерархии предков объекта), когда это непозволительно
дорого для приложения.
 избежать наследования создателя объекта (object creator) в клиентском
приложении, как это делает паттерн abstract factory.
Используйте этот шаблон проектирования, когда системe безразлично как именно в
ней создаются, компонуются и представляются продукты:

 инстанцируемые классы определяются во время выполнения, например с помощью


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

Паттерн Прототип поручает создание копий самим копируемым объектам. Он вводит


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

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

В промышленном производстве прототипы создаются перед основной партией


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

Пример деления клетки.


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

Плюсы

 контролируемый доступ к единственному экземпляру.

Минусы

 глобальные объекты могут быть вредны для объектного программирования, в


некоторых случаях приводят к созданию немасштабируемого проекта;
 усложняет написание модульных тестов и следование TDD;
 усложняется контроль за межпоточными гонками и задержками.

Применение

 должен быть ровно один экземпляр некоторого класса, легко доступный всем
клиентам;
 единственный экземпляр должен расширяться путём порождения подклассов, и
клиентам нужно иметь возможность работать с расширенным экземпляром без
модификации своего кода.

Примеры использования

 Ведение отладочного файла для приложения.


 В любом приложении для iOS существует класс AppDelegate, являющийся
делегатом приложения.

ПРОБЛЕМА
Одиночка решает сразу две проблемы, нарушая принцип единственной
ответственности класса.

1. Гарантирует наличие единственного экземпляра класса. Чаще всего это


полезно для доступа к какому-то общему ресурсу, например, базе данных.

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


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

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


так как конструктор класса всегда возвращает новый объект.

2. Предоставляет глобальную точку доступа. Это не просто глобальная


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

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

РЕШЕНИЕ
Все реализации одиночки сводятся к тому, чтобы скрыть конструктор по умолчанию и
создать публичный статический метод, который и будет контролировать жизненный
цикл объекта-одиночки.

Если у вас есть доступ к классу одиночки, значит, будет доступ и к этому
статическому методу. Из какой точки кода вы бы его ни вызвали, он всегда будет
отдавать один и тот же объект.

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

Вам также может понравиться