CodeLAB
на главную карта сайта обратная связь
каталог | задачи | паттерны | исходники | стат | форумы | ссылки
 гость
искать в
Главная >> Каталог задач >> Паттерны >> Порождающие >> Прототип (Prototype)

<< назад
распечатать обсудить >>


Прототип (Prototype)
реализации: java, количество: 2

Aвтор: this
Дата: 22.06.2007
Просмотров: 48400
Рейтинг: 0/0,0(0)
+
реализации(исходники) +добавить

Имя

«Паттерн
Prototype» codelab.ru codelab.ru оригинал источник

Прототип – паттерн, порождающий объекты. codelab.ru codelab.ru оригинал источник

Условия, Задача, Назначение

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

Мотивация

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

источник codelab.ru codelab.ru оригинал

Предположим, что каркас предоставляет абстрактный класс Graphic для графических компонентов вроде нот и нотных станов, а также абстрактный класс Tool для определения инструментов в палитре. Кроме того, в каркасе имеется предопределенный подкласс GraphicTool для инструментов, которые создают графические объекты и добавляют их в документ. Однако класс GraphicTool создает некую проблему для проектировщика каркаса. Классы нот и нотных станов специфичны для нашего приложения, а класс GraphicTool принадлежит каркасу. Этому классу ничего неизвестно о том, как создавать экземпляры наших музыкальных классов и добавлять их в партитуру. Можно было бы породить от GraphicTool подклассы для каждого вида музыкальных объектов, но тогда оказалось бы слишком много классов, отличающихся только тем, какой музыкальный объект они инстанцируют. Мы знаем, что гибкой альтернативой порождению подклассов является композиция. Вопрос в том, как каркас мог бы воспользоваться ею для параметризации экземпляров GraphicTool классом того объекта Graphic, который предполагается создать. codelab.ru оригинал источник codelab.ru
Решение - заставить GraphicTool создавать новый графический объект, копируя или «клонируя» экземпляр подкласса класса Graphic. Этот экземпляр мы будем называть прототипом. GraphicTool параметризуется прототипом, который он должен клонировать и добавить в документ. Если все подклассы Graphic поддерживают операцию Clone, то GraphicTool может клонировать любой вид графических объектов. codelab.ru оригинал источник codelab.ru
Итак, в нашем музыкальном редакторе каждый инструмент для создания музыкального объекта - это экземпляр класса GraphicTool, инициализированный тем или иным прототипом. Любой экземпляр GraphicTool будет создавать музыкальный объект, клонируя его прототип и добавляя клон в партитуру. источник codelab.ru codelab.ru оригинал
Можно воспользоваться паттерном прототип, чтобы еще больше сократить число классов. Для целых и половинных нот у нас есть отдельные классы, но, быть может, это излишне. Вместо этого они могли бы быть экземплярами одного и того же класса, инициализированного разными растровыми изображениями и длительностями звучания. Инструмент для создания целых нот становится просто объектом класса GraphicTool, в котором прототип MusicalNote инициализирован целой нотой. Это может значительно уменьшить число классов в системе. Заодно упрощается добавление нового вида нот в музыкальный редактор. codelab.ru codelab.ru оригинал источник
оригинал codelab.ru codelab.ru источник

Признаки применения, использования паттерна Прототип (Prototype)

Выражаясь общими словами снова можно дать уже довольно знакомый совет: «Используйте паттерн прототип, когда система не должна зависеть от того, как в ней создаются, компонуются и представляются продукты». Теперь более конкретные случаи: оригинал codelab.ru codelab.ru источник
  1. Инстанцируемые классы определяются во время выполнения, например, с помощью динамической загрузки. Поэтому вдвойне проблематично сначала динамически определять к какому конкретному классу относится объект, при этом не ошибиться определить именно самого потомка, а не родителя этого класса например, + затем еще затем активировать еще соответствующую фабрику для создания объектов такого рода и т.д. оригинал codelab.ru codelab.ru источник
  2. Для того чтобы избежать построения иерархий классов или фабрик, параллельных иерархии классов продуктов. Ну это известное дело – с ростом иерархии фабрик, растет соответственно иерархия продуктов, различных helper-ов и т.д. codelab.ru оригинал codelab.ru источник
  3. Экземпляры класса могут находиться в одном из не очень большого числа различных состояний, так что может оказаться целесообразней устанавливать соответствующее число прототипов и клонировать их, а не инстанцировать каждый раз класс вручную в подходящем состоянии. codelab.ru codelab.ru оригинал источник

Решение

оригинал codelab.ru источник codelab.ru

codelab.ru codelab.ru оригинал источник

Участники паттерна Прототип (Prototype)

  1. Prototype (Graphic) – прототип.
    Объявляет операцию собственного клонирования, и прикладной интерфейс для работы с объектами своего разряда. codelab.ru оригинал codelab.ru источник
  2. ConcretePrototype ( Staff - нотный стан, WholeNote - целая нота, HalfNote - половинная нота) - конкретный прототип.
    Реализует операцию собственного клонирования, при необходимости переопределяет api методы своего интерфейса. оригинал codelab.ru codelab.ru источник
  3. Client (GraphicTool) – клиент.
    Создает новый объект, обращаясь к прототипу с запросом клонировать себя, затем, пользуясь его интерфейсом, выполняет с полученным клоном установленные бизнес манипуляции. codelab.ru codelab.ru источник оригинал

Схема использования паттерна Прототип (Prototype)

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

Результаты

У прототипа те же самые результаты, что у абстрактной фабрики и строителя: он скрывает от клиента конкретные классы продуктов, уменьшая тем самым число известных клиенту имен. Кроме того, все эти паттерны позволяют клиентам работать со специфичными для приложения классами без модификаций. источник codelab.ru оригинал codelab.ru
Ниже перечислены дополнительные преимущества паттерна прототип: codelab.ru codelab.ru оригинал источник
  1. Добавление и удаление продуктов во время выполнения.
    Прототип позволяет включать новое семейство конкретных классов продуктов в систему, просто сообщив клиенту о новом экземпляре-прототипе. Это несколько более гибкое решение по сравнению с тем, что удастся сделать с помощью других порождающих паттернов, ибо клиент может устанавливать и удалять прототипы во время выполнения. источник оригинал codelab.ru codelab.ru
  2. Спецификация новых объектов путем изменения значений.
    Динамичные системы позволяют определять поведение за счет композиции объектов - например, путем задания значений переменных объекта, - а не с помощью определения новых классов. По сути дела, вы определяете новые виды объектов, инстанцируя уже существующие классы и регистрируя их экземпляры как прототипы клиентских объектов. Клиент может изменить поведение, делегируя свои обязанности прототипу, и соответственно стать в некотором роде параметризированным от прототипа. Что позволит, лишь подсовывая в качестве прототипа новый скомпонованный объект – легко менять поведение системы.
    Такой дизайн позволяет пользователям определять новые классы без программирования. Фактически клонирование объекта аналогично инстанцированию класса. Паттерн прототип может резко уменьшить число необходимых системе классов. В нашем музыкальном редакторе с помощью одного только класса GraphicTool удастся создать бесконечное разнообразие музыкальных объектов. источник codelab.ru оригинал codelab.ru
  3. Специфицирование новых объектов путем изменения структуры. Многие приложения строят объекты из крупных и мелких составляющих. Например, редакторы для проектирования печатных плат создают электрические схемы из подсхем. Такие приложения часто позволяют инстанцировать сложные, определенные пользователем структуры, скажем, для многократного использования некоторой подсхемы.
    Паттерн прототип поддерживает и такую возможность. Мы просто добавляем подсхему как прототип в палитру доступных элементов схемы. При условии, что объект, представляющий составную схему, реализует операцию Clone как глубокое копирование, схемы с разными структурами могут выступать в качестве прототипов, что позволит одинаково фабриковать как сложные составные схемы, так и совсем простые и далее унифицировано работать с полученными сущностями.
    Таким образом, в случае объектов с композицией многих других объектов, имеющих глубокую иерархию (притом что имеется поддержка глубокого копирования) – мы получаем главное преимущество: код конструирования таких объектов – не зависит от глубины иерархии отдельных составляющих его элементов-сущностей, все это делается одной операцией, одинаково для всех объектов с любой композицией вложенных элементов. источник codelab.ru codelab.ru оригинал
  4. Уменьшение числа подклассов.
    Паттерн фабричный метод часто порождает иерархию классов Creator, параллельную иерархии классов продуктов. Прототип позволяет клонировать прототип, а не запрашивать фабричный метод создать новый объект. Поэтому иерархия класса Creator становится вообще ненужной. codelab.ru источник codelab.ru оригинал
  5. Динамическое конфигурирование приложения классами.
    Некоторые среды позволяют динамически загружать классы в приложение во время его выполнения. Паттерн прототип - это ключ к применению таких возможностей в таком языке. codelab.ru источник codelab.ru оригинал
  codelab.ru оригинал источник codelab.ru
Основной недостаток паттерна прототип заключается в том, что каждый подкласс класса Prototype должен реализовывать операцию Clone, а это далеко не всегда просто. Например, сложно добавить операцию Clone, когда рассматриваемые классы уже существуют. Проблемы возникают и в случае, если во внутреннем представлении объекта есть другие объекты или наличествуют круговые ссылки. источник codelab.ru оригинал codelab.ru
codelab.ru источник оригинал codelab.ru

Пример

Здесь имеем очень интересную возможность осуществить оптимизацию программы создания авто-парка. Вспомним, что там для создания нового семейства машин автопарка создается новая конкретная фабрика, переопределяющая фабричные методы создания отдельных видов автомобилей. Применив паттерн прототип – мы совсем избавляется от дополнительного создания подклассов для каждого нового семейства. оригинал источник codelab.ru codelab.ru
Итак, вашему вниманию предлагается следующая версия фабрики авто-парка: PrototypeFleetFactory. оригинал codelab.ru источник codelab.ru
  codelab.ru codelab.ru источник оригинал
Конструктору просто передаем прототипы легкового автомобиля, автобуса и грузовика и затем в функциях добавления – просто клонируем их, устанавливая новый номер. оригинал codelab.ru источник codelab.ru
Теперь для создания авто-парка с другим семейством автомобилей, клиенту вовсе не нужно инстанцировать новый подкласс фабрики парка, вместо этого он снова использует PrototypeFleetFactory, лишь передавая туда другие объекты-продукты относящиеся уже к другому семейству: PrototypeFleetRun. источник оригинал codelab.ru codelab.ru
codelab.ru источник оригинал codelab.ru
Обратите внимание на замещение метода GetFactory: при переходе от одного семейства машин к другому теперь нужно лишь передать конструктору другие объекты автомобилей. Номер при этом не важен – он далее сам заполняется в методе CreateFleet(). +дабы не дублировать много кода – просто наследуемся он предыдущей реализации клиента по создания парка (FleetRun). При этом остается лишь переопределить один бизнес-метод – GetFactory (метод main не переопределяется, это скорее системный метод, не относящийся к бизнес-логике – в нашем случае можно так сказать), работа остальных наследуется и не претерпевает каких-либо изменений, т.к. в них везде используется интерфейс абстрактной фабрики (FleetFactory), к которой принадлежит и PrototypeFleetFactory в том числе. источник оригинал codelab.ru codelab.ru
оригинал источник codelab.ru codelab.ru
  codelab.ru оригинал источник codelab.ru
codelab.ru источник оригинал codelab.ru
оригинал codelab.ru источник codelab.ru

Известные применения паттерна Прототип (Prototype)

Быть может, впервые паттерн прототип был использован в системе Sketchpad Ивана Сазерленда (Ivan Sutherland). Первым широко известным применением этого паттерна в объектно-ориентированном языке была система ThingLab, в которой пользователи могли сформировать составной объект, а затем превратить его в прототип, поместив в библиотеку повторно используемых объектов. Ад ель Голдберг и Давид Робсон упоминают прототипы в качестве паттернов в работе, но Джеймс Коплиен рассматривает этот вопрос гораздо шире. Он описывает связанные с прототипом идиомы языка C++ и приводит много примеров и вариантов. оригинал codelab.ru источник codelab.ru
Etgdb - это оболочка отладчиков на базе ЕТ++, где имеется интерфейс вида point-and-click (укажи и щелкни) для различных командных отладчиков. Для каждого из них есть свой подкласс DebuggerAdaptor. Например, GdbAdaptor настраивает etgdb на синтаксис команд GNU gdb, a SunDbxAdaptor - на отладчик dbx компании Sun. Набор подклассов DebuggerAdaptor не «зашит» в etgdb. Вместо этого он получает имя адаптера из переменной среды, ищет в глобальной таблице прототип с указанным именем, а затем его клонирует. Добавить к etgdb новые отладчики можно, связав ядро с подклассом DebuggerAdaptor, разработанным для этого отладчика. оригинал codelab.ru источник codelab.ru
Библиотека приемов взаимодействия в программе Mode Composer хранит прототипы объектов, поддерживающих различные способы интерактивных отношений. Любой созданный с помощью Mode Composer способ взаимодействия можно применить в качестве прототипа, если поместить его в библиотеку. Паттерн прототип позволяет программе поддерживать неограниченное число вариантов отношений. codelab.ru источник codelab.ru оригинал
Пример музыкального редактора, обсуждавшийся в начале этого раздела, основан на каркасе графических редакторов Unidraw. codelab.ru оригинал codelab.ru источник
codelab.ru источник codelab.ru оригинал

Родственные паттерны

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


Реализации: java(2)   +добавить реализацию

1) PrototypeFleetFactory.java, code #431[автор:this]
2) PrototypeFleetRun.java, code #432[автор:this]


<< назад наверх
распечатать обсудить >>

 
каталог | задачи | паттерны | исходники | стат | форумы | карта сайта | контакты | ссылки 
© 2000-2017 CodeLAB Group
  Все права защищены
Страница сгенерирована за 0.040374 секунд
Количество запросов к БД: 14, gzip: 17.5kb/66.3kb(74%)