Название и классификация образца
Поможем в ✍️ написании учебной работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

Фабричный метод – паттерн, порождающий классы.

Назначение

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

Известен также под именем

Virtual Constructor (виртуальный конструктор).

Factory Method : мотивация

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

Рассмотрим каркас для приложений, способных представлять пользователю сразу несколько документов. Две основных абстракции в таком каркасе – это классы Application и Document. Оба класса абстрактные, поэтому клиенты должны порождать от них подклассы для создания специфичных для приложения реализаций. Например, чтобы создать приложение для рисования, мы определим классы DrawingApplication и DrawingDocument. Класс Application отвечает за управление документами и создает их по мере необходимости, допустим, когда пользователь выбирает из меню пункт Open (открыть) или New (создать).

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

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

Рисунок 5

Factory Method: применимость

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

• Классу заранее неизвестно, объекты каких классов ему нужно создавать;

• Класс спроектирован так, чтобы объекты, которые он создает, специфицировались подклассами;

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

Factory Method: структура

Рисунок 6

Участники

Product (Document) – продукт - определяет интерфейс объектов, создаваемых фабричным методом;

ConcreteProduct (MyDocument) - конкретный продукт - реализует интерфейс Product;

Creator (Application) – создатель - объявляет фабричный метод, возвращающий объект типа Product. Creator может также определять реализацию по умолчанию фабричного метода, который возвращает объект ConcreteProduct; может вызывать фабричный метод для создания объекта Product;

ConcreteCreator (MyApplication) - конкретный создатель - замещает фабричный метод, возвращающий объект ConcreteProduct.

Реализация

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

Factory Method: особенности

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

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

Применение в Java API

Каждый объект URL имеет связанный с ним объект URLConnection. Объекты URLConnection имеют метод getContent, который возвращает содержимое URL, упакованное в соответствующем обекте. Например, если URL содержит файл gif, то метод getContent объекта URLConnection вернет объект Image. Объекты URLConnection играют роль инициатора запроса создания в паттерне Фабричный метод. Они делегируют функции метода getContent объекту класса ContentHandler. Это абстрактный класс, который играет роль Product и имеет информацию об управлении содержимым определенного типа. Объект URLConnection получает объект класса ContentHandler через объект класса ContentHandlerFactory. Это абстрактный класс, который участвует в паттерне Фабричный метод в качестве интерфейса класса-фабрики. Класс URLConnection имеет также метод setContentHandlerFactory.

Паттерн Prototype.

Название

Прототип – паттерн, порождающий объекты.

Назначение

Задает виды создаваемых объектов с помощью экземпляра-прототипа и создает новые объекты путем копирования этого прототипа.

Prototype: мотивация

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

Предположим, что каркас предоставляет абстрактный класс Graphic для графических компонентов вроде нот и нотных станов, а также абстрактный классTool для определения инструментов в палитре. Кроме того, в каркасе имеется предопределенный подкласс GraphicTool для инструментов, которые создают графические объекты и добавляют их в документ.

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

Решение - заставить GraphicTool создавать новый графический объект, копируя или «клонируя» экземпляр подкласса класса Graphic. Этот экземпляр мы будем называть прототипом. GraphicTool параметризуется прототипом, который он должен клонировать и добавить в документ. Если все подклассы Graphic поддерживают операцию clone, то GraphicTool может клонировать любой вид графических объектов.

Итак, в нашем музыкальном редакторе каждый инструмент для создания музыкального объекта - это экземпляр класса GraphicTool, инициализированный тем или иным прототипом. Любой экземпляр GraphicTool будет создавать музыкальный объект, клонируя его прототип и добавляя клон в партитуру.

Можно воспользоваться паттерном прототип, чтобы еще больше сократить число классов. Для целых и половинных нот у нас есть отдельные классы, но, быть может, это излишне. Вместо этого они могли бы быть экземплярами одного и того же класса, инициализированного разными растровыми изображениями и длительностями звучания. Инструмент для создания целых нот становится просто объектом класса GraphicTool, в котором прототип MusicalNote инициализирован целой нотой. Это может значительно уменьшить число классов в системе. Заодно упрощается добавление нового вида нот в музыкальный редактор.

Рисунок 7

Prototype: применимость

Используйте паттерн прототип, когда система не должна зависеть от того, как в ней создаются, компонуются и представляются продукты:

• Инстанцируемые классы определяются во время выполнения, например с помощью динамической загрузки;

• Для того чтобы избежать построения иерархий классов или фабрик, параллельных иерархии классов продуктов;

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

Prototype: структура

Рисунок 8

Участники

Prototype (Graphic) – прототип - объявляет интерфейс для клонирования самого себя;

ConcretePrototype ( S t a f f - нотный стан, WholeNote - целая нота, Half Note - половинная нота) - конкретный прототип - реализует операцию клонирования себя;

Client (GraphicTool) – клиент - создает новый объект, обращаясь к прототипу с запросом клонировать себя.

Отношения

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

Реализация

1. Использование диспетчера прототипов. Если число прототипов в системе не фиксировано (то есть они могут создаваться и уничтожаться динамически), ведите реестр доступных прототипов. Клиенты должны не управлять прототипами самостоятельно, а сохранять и извлекать их из реестра. Клиент запрашивает прототип из реестра перед его клонированием. Такой реестр мы будем называть диспетчером прототипов. Диспетчер прототипов - это ассоциативное хранилище, которое возвращает прототип, соответствующий заданному ключу. В нем есть операции для регистрации прототипа с указанным ключом и отмены регистрации. Клиенты могут изменять и даже «просматривать» реестр во время выполнения, а значит, расширять систему и вести контроль над ее состоянием без написания кода;

2. Реализация операции clone. Самая трудная часть паттерна прототип - правильная реализация операции clone. Особенно сложно это в случае, когда в структуре объекта есть круговые ссылки. В большинстве языков имеется некоторая поддержка для клонирования объектов. Но эти средства не решают проблему «глубокого и поверхностного копирования». Суть ее в следующем: должны ли при клонировании объекта клонироваться также и его переменные экземпляра или клон просто разделяет с оригиналом эти переменные? Поверхностное копирование просто, и часто его бывает достаточно. Но для клонирования прототипов со сложной структурой обычно необходимо глубокое копирование, поскольку клон должен быть независим от оригинала. Поэтому нужно гарантировать, что компоненты клона являются клонами компонентов прототипа. При клонировании вам приходится решать, что именно может разделяться и может ли вообще;

3. Инициализация клонов. Хотя некоторым клиентам вполне достаточно клона как такового, другим нужно инициализировать его внутреннее состояние полностью или частично. Обычно передать начальные значения операции clone невозможно, поскольку их число различно для разных классов прототипов. Для некоторых прототипов нужно много параметров инициализации, другие вообще ничего не требуют. Передача clone параметров мешает построению единообразного интерфейса клонирования. Может оказаться, что в ваших классах прототипов уже определяются операции для установки и очистки некоторых важных элементов состояния. Если так, то этими операциями можно воспользоваться сразу после клонирования. В противном случае, возможно, понадобится ввести операцию Initialize, которая принимает начальные значения в качестве аргументов и соответственно устанавливает внутреннее состояние клона. Будьте осторожны, если операция clone реализует глубокое копирование: копии может понадобиться удалять (явно или внутри Initialize) перед повторной инициализацией.

Применение в Java API

Шаблон Prototype очень важен для JavaBeans – это экземпляры классов, которые удовлетворяют определённым соглашениям об именах. Соглашения об именах позволяют программе создания компонентов (Beans) знать, как их настраивать. После настройки объекта компонента с целью использования его в приложении, объект сохраняется в файле, который загружается приложением на стадии выполнения.

Паттерн Singleton.

Название

Одиночка – паттерн, порождающий объекты.

Назначение

Гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа.

Singleton: применимость

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

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

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

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

Singleton: структура

Рисунок 9

Участники

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

Реализация

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

Применение в Java A PI

java.lang.Runtime – это класс-Одиночка. Он имеет строго один экземпляр, не имеет доступных конструкторов, чтобы получить ссылку на единственный экземпляр нужно вызвать статический метод getRuntime.

Паттерн Adapter.

Дата: 2019-02-25, просмотров: 247.