Паттерны проектирования и их представление в нотации UML. Паттерны ооп в метафорах

12.07.2019

Приложения Laravel, нам неплохо было бы понять архитектуру каркаса приложения . Некоторые могут спросить: Зачем это нужно? Смысл забивать себе голову разной теоретической чепухой?
Постараюсь ответить на этот вопрос примером из жизни:

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

Я думаю, не стоит описывать, что у вас получится в итоге, ясно только одно - ничего хорошего.

Ну и более приближенный к теме Laravel 4 ответ: Понимание архитектуры приложения , знание основ паттернов (шаблонов) проектирования , помогут вам понять, почему следует использовать именно этот каркас web-приложения, оценить его слабые и сильные стороны. Так же вы получите ответ, почему так сильно изменился Laravel 4 по сравнению с Laravel 3.

Для тех, кто все же решил изучить теорию, прежде чем приступить к практике, советую: запаситесь терпением.

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

Определения

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

Паттерны это не так сложно как кажется

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

На самом деле паттерны не так сложны для понимания, как кажется на первый взгляд. Давайте проиллюстрируем их примерами, все сразу станет намного понятнее.

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

  1. Вася и Петя встретились.
  2. Вася протянул Пете руку.
  3. Петя сказал «Здравствуй Вася» .
  4. Вася ответил «Здравствуй Петя» .
  5. Вася спросил «Ты принес мне диск с курсовой?» .
  6. Петя ответил «Да, принес» .
  7. Вася полез в карман и достал деньги.
  8. Вася отсчитал 100$.
  9. Вася передал деньги Пете.
  10. Петя принял деньги от Васи.
  11. Петя пересчитал деньги.
  12. Петя кивнул головой - подтверждая, что сумма соответствует цене за диск.
  13. Петя положил деньги в карман.
  14. Петя достал диск.
  15. Петя передал диск Васе.
  16. Вася принял диск от Пети.
  17. Вася положил диск в карман.

Теперь разобьём эту программу на отдельные части:

  1. Начало программы.
  2. Встреча.
  3. Обмен приветствиями.
  4. Проверка наличия «данных» .
  5. Передача данных «деньги» .
  6. Списание данных «деньги» .
  7. Проверка данных «деньги» .
  8. Запись данных «деньги» .
  9. Передача данных «диск» .
  10. Списание данных «диск» .
  11. Запись данных «диск» .
  12. Конец программы.

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

Теперь разбиваем алгоритм на составляющие так:

  1. Общение.
  2. Обмен данными.
  3. Проверка условий.
  4. Действия.

У нас как раз и получился набор паттернов (правда очень абстрактный). Зато этот архитектурный паттерн или программная парадигма описывает обмен данными практически любого вида и любой сложности. По сути это аналог всем известного MVC .

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

Давайте попробуем составить схему таких паттернов самостоятельно:

  1. Общение
    1. Установление контакта
    2. Передача запросов между пользователем и системой
  2. Обмен данными
    1. Передача данных запроса в направлении в систему
    2. Передача данных запроса в направлении из системы
    3. Передача команд на проверку условий
    4. Передача команд на передачу данных
  3. Проверка условий
    1. Проверка условий передачи данных
    2. Подтверждение проверки условий
  4. Действия
    1. Извлечение данных из хранилища «А»
    2. Передача данных в хранилище «А»

В итоге у нас получилась своя схема паттернов.

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

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

Паттерны бывают разными

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

  • Классификация по масштабу
  • Классификация по стилю
  • Классификация по применению

Классификация по масштабу

Самая часто используемая классификация - это классификация по масштабу. Чаще всего она применяется для паттернов проектирования и делится на три слоя по детализации:

  • Архитектурные паттерны - наивысший слой детализации, используются для описания структуры программы в целом.
  • Паттерны проектирования - средний слой детализации, описывают компоненты отдельных архитектурных паттернов и реализацию их взаимодействия.
  • Идиомы - низший слой детализации, описывают реализацию отдельных решений проблем применительно к конкретному языку программирования. Следует учитывать, что зачастую идиомы для различных языков программирования имеют различную реализацию, или не имеют таковой вовсе. Примером могут служить указатели в памяти для реализации в Assembler , они имеют абсолютно другую реализацию в Си и не имеют реализации в С# , так как там проблема с утечкой памяти не существует ибо есть мусора ...

Классификация по стилю

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

Классификация по применению

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

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

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

Заключение

Какие преимущества дают нам паттерны? Отвечу на этот вопрос, цитируя John Vlissides ( Влиссидес):

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

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

Для тех, кого заинтересовали паттерны, советую найти и почитать книги:

  • Э. Гамма, Р. Хелм, Р. Джонсон, Д. Влиссидес: Приемы ООП. проектирования .
  • Джон Влиссидес: шаблонов проектирования . Дополнительные штрихи.

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

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

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

Немного истории

Впервые, в конце 1970-х годов Кристофером Александром был разработан каталог паттернов, предназначенных для проектирования зданий и городов . В конце 1980-х годов Кент Бек и Вард Каннингем попытались перенести идеи Александра в область разработки ПО, составив 5 небольших паттернов для проектирования пользовательских интерфейсов на языке Smalltalk. В 1989 Джеймс Коплиен в целях обучения С++ внутри компании AT&T составил каталог идиом С++ (разновидность паттернов, специфичных для языка программирования), а в 1991 на его основе вышла в свет книга "Advanced C++ Programming Styles and Idioms" (имеется русский перевод ).

Однако по настоящему популярным применение паттернов в индустрии разработки программного обеспечения стало после того, как в 1994 был опубликован каталог, включающий 23 паттерна объектно-ориентированного проектирования . Этот каталог настолько популярен, что часто упоминается как паттерны GoF ("Gang of Four" или "банда четырех" по числу авторов).

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

Классификация паттернов

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

В настоящее время наиболее популярными паттернами являются паттерны проектирования. Одной из распространенных классификаций таких паттернов является классификация по степени детализации и уровню абстракции рассматриваемых систем. Согласно , паттерны проектирования программных систем делятся на следующие категории:

  • Архитектурные паттерны
  • Паттерны проектирования
  • Идиомы

Архитектурные паттерны , являясь наиболее высокоуровневыми паттернами, описывают структурную схему программной системы в целом. В данной схеме указываются отдельные функциональные составляющие системы, называемые подсистемами, а также взаимоотношения между ними. Примером архитектурного паттерна является хорошо известная программная парадигма "модель-представление-контроллер" (model-view-controller - MVC).

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

В русскоязычной литературе обычно встречаются несколько вариантов перевода оригинального названия design patterns - паттерны проектирования , шаблоны проектирования , образцы . Здесь в основном используется первый вариант, иногда второй.

Идиомы , являясь низкоуровневыми паттернами, имеют дело с вопросами реализации какой-либо проблемы с учетом особенностей данного языка программирования. При этом часто одни и те же идиомы для разных языков программирования выглядят по-разному или не имеют смысла вовсе. Например, в C++ для устранения возможных утечек памяти могут использоваться интеллектуальные указатели. Интеллектуальный указатель содержит указатель на участок динамически выделенной памяти, который будет автоматически освобожден при выходе из зоны видимости. В среде Java такой проблемы просто не существует, так как там используется автоматическая сборка мусора. Обычно, для использования идиом нужно глубоко знать особенности применяемого языка программирования.

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

Описание паттернов

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

  1. Название паттерна. Представляет собой уникальное смысловое имя, однозначно определяющее данную задачу или проблему и ее решение.
  2. Решаемая задача. Здесь дается понимание того, почему решаемая проблема действительно является таковой, четко описывает ее границы.
  3. Решение. Здесь указывается, как именно данное решение связано с проблемой, приводится пути ее решения.
  4. Результаты использования паттерна. Обычно приводятся достоинства, недостатки и компромиссы.

Результаты применения паттернов

  1. Они (паттерны) позволяют суммировать опыт экспертов и сделать его доступным рядовым разработчикам.
  2. Имена паттернов образуют своего рода словарь, который позволяет разработчикам лучше понимать друг друга.
  3. Если в документации системы указано, какие паттерны в ней используются, это позволяет читателю быстрее понять систему.
  4. Паттерны упрощают реструктуризацию системы независимо от того, использовались ли паттерны при ее проектировании.

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

Используемая литература

При подготовке материалов из раздела Design Patterns использовалась следующая литература:

  1. Alexander С., Ishikawa S., Silverstein M. A Pattern Language: Towns, Buildings, Construction. Oxford University Press, 1977.
  2. Buschmann F., Meunier R., Rohnert H., Sommerlad P., Stal M. Pattern-Oriented Software Architecture, Volume 1, A System of Patterns. Wiley, 1996, 476 pages
  3. Александреску А. Современное проектирование на C++ (серия C++ in Depth). - М.: Издательский дом "Вильямс", 2008.-336с
  4. Влиссидес Дж. Применение шаблонов проектирования. Дополнительные штрихи. - М.: Издательский дом "Вильямс", 2003.-144с
  5. Гамма Э., Хелм Р., Джонсон Р., Влиссидес Дж. Приемы объектно-ориентированного проектирования. Паттерны проектирования. - СПб.: Питер, 2001.-368с
  6. Кериевски Дж. Рефакторинг с использованием шаблонов. - М.: Издательский дом "Вильямс", 2006.-400с
  7. Коплиен Дж. Программирование на C++. Классика CS. - СПб.: Питер, 2005.-479с
  8. Ларман К. Применение UML и шаблонов проектирования, 2-е издание. - М.: Издательский дом "Вильямс", 2004.-624с
  9. Эккель Б. Философия C++. Практическое программирование C++. Том 2. - СПб.: Питер, 2004.-608с

Перед началом статьи, я хочу предложить доклад своего товарища — Дениса Порпленко о паттернах проектирования в программировании:

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

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

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

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

Основные шаблоны программирования

Фундаментальные

Шаблон делегирования (Delegation pattern) — Объект внешне выражает некоторое поведение, но в реальности передаёт ответственность за выполнение этого поведения связанному объекту.
Шаблон функционального дизайна (Functional design) — Гарантирует, что каждый модуль компьютерной программы имеет только одну обязанность и исполняет её с минимумом побочных эффектов на другие части программы.
Неизменяемый интерфейс (Immutable interface) — Создание неизменяемого объекта.
Интерфейс (Interface) — Общий метод для структурирования компьютерных программ для того, чтобы их было проще понять.
Интерфейс-маркер (Marker interface) — В качестве атрибута (как пометки объектной сущности) применяется наличие или отсутствие реализации интерфейса-маркера. В современных языках программирования вместо этого могут применяться атрибуты или аннотации.
Контейнер свойств (Property container) — Позволяет добавлять дополнительные свойства для класса в контейнер (внутри класса), вместо расширения класса новыми свойствами.
Событийный шаблон (Event channel) — Расширяет шаблон Publish/Subscribe, создавая централизованный канал для событий. Использует объект-представитель для подписки и объект-представитель для публикации события в канале. Представитель существует отдельно от реального издателя или подписчика. Подписчик может получать опубликованные события от более чем одного объекта, даже если он зарегистрирован только на одном канале.

Порождающие шаблоны

Порождающие шаблоны (Creational) — шаблоны проектирования, которые абстрагируют процесс инстанцирования. Они позволяют сделать систему независимой от способа создания, композиции и представления объектов. Шаблон, порождающий классы, использует наследование, чтобы изменять инстанцируемый класс, а шаблон, порождающий объекты, делегирует инстанцирование другому объекту.
Абстрактная фабрика (Abstract factory) — Класс, который представляет собой интерфейс для создания компонентов системы.
Строитель (Builder) — Класс, который представляет собой интерфейс для создания сложного объекта.
Фабричный метод (Factory method) — Определяет интерфейс для создания объекта, но оставляет подклассам решение о том, какой класс инстанцировать.
Отложенная инициализация (Lazy initialization) — Объект, инициализируемый во время первого обращения к нему.
Пул одиночек (Multiton) — Гарантирует, что класс имеет поименованные экземпляры объекта и обеспечивает глобальную точку доступа к ним.
Объектный пул (Object pool) — Класс, который представляет собой интерфейс для работы с набором инициализированных и готовых к использованию объектов.
Прототип (Prototype) — Определяет интерфейс создания объекта через клонирование другого объекта вместо создания через конструктор.
Получение ресурса есть инициализация (Resource acquisition is initialization (RAII)) — Получение некоторого ресурса совмещается с инициализацией, а освобождение - с уничтожением объекта.
Одиночка (Singleton) — Класс, который может иметь только один экземпляр.

Структурные шаблоны

Структурные шаблоны (Structural) определяют различные сложные структуры, которые изменяют интерфейс уже существующих объектов или его реализацию, позволяя облегчить разработку и оптимизировать программу.
Адаптер (Adapter / Wrapper) — Объект, обеспечивающий взаимодействие двух других объектов, один из которых использует, а другой предоставляет несовместимый с первым интерфейс.
Мост (Bridge) — Структура, позволяющая изменять интерфейс обращения и интерфейс реализации класса независимо.
Компоновщик (Composite) — Объект, который объединяет в себе объекты, подобные ему самому.
Декоратор или Обёртка (Decorator) или (Wrapper) — Класс, расширяющий функциональность другого класса без использования наследования.
Фасад (Facade) — Объект, который абстрагирует работу с несколькими классами, объединяя их в единое целое.
Единая точка входа (Front controller) — Обеспечивает унифицированный интерфейс для интерфейсов в подсистеме. Front Controller определяет высокоуровневый интерфейс, упрощающий использование подсистемы.
Приспособленец (Flyweight) — Это объект, представляющий себя как уникальный экземпляр в разных местах программы, но по факту не являющийся таковым.
Заместитель (Proxy) — Объект, который является посредником между двумя другими объектами, и который реализует/ограничивает доступ к объекту, к которому обращаются через него.

Поведенческие шаблоны

Поведенческие шаблоны (Behavioral) определяют взаимодействие между объектами, увеличивая таким образом его гибкость.
Цепочка обязанностей (Chain of responsibility) — Предназначен для организации в системе уровней ответственности.
Команда (Command) — Представляет действие. Объект команды заключает в себе само действие и его параметры.
Интерпретатор (Interpreter) — Решает часто встречающуюся, но подверженную изменениям, задачу.
Итератор (Iterator) — Представляет собой объект, позволяющий получить последовательный доступ к элементам объекта-агрегата без использования описаний каждого из объектов, входящих в состав агрегации.
Посредник (Mediator) — Обеспечивает взаимодействие множества объектов, формируя при этом слабую связанность и избавляя объекты от необходимости явно ссылаться друг на друга.
Хранитель (Memento) — Позволяет не нарушая инкапсуляцию зафиксировать и сохранить внутренние состояния объекта так, чтобы позднее восстановить его в этих состояниях.
Нулевой объект (Null object) — Предотвращает нулевые указатели, предоставляя объект «по умолчанию».
Наблюдатель (Observer) — Определяет зависимость типа «один ко многим» между объектами таким образом, что при изменении состояния одного объекта все зависящие от него оповещаются об этом событии.
Слуга (Servant) — Используется для обеспечения общей функциональности группе классов.
Спецификация (Specification) — Служит для связывания бизнес-логики.
Состояние (State) — Используется в тех случаях, когда во время выполнения программы объект должен менять своё поведение в зависимости от своего состояния.
Стратегия (Strategy) — Предназначен для определения семейства алгоритмов, инкапсуляции каждого из них и обеспечения их взаимозаменяемости.
Шаблонный метод (Template method) — Определяет основу алгоритма и позволяет наследникам переопределять некоторые шаги алгоритма, не изменяя его структуру в целом.
Посетитель (Visitor) — Описывает операцию, которая выполняется над объектами других классов. При изменении класса Visitor нет необходимости изменять обслуживаемые классы.
Простая политика — я знаю, что такой паттерн есть, но что он означает, пока не нашел. Если будет инфа — скиньте в комментариях.
Слушатель (Event listener) — аналогично
Одноразовый посетитель (Single-serving visitor) — Оптимизирует реализацию шаблона посетитель, который инициализируется, единожды используется, и затем удаляется.
Иерархический посетитель (Hierarchical visitor) — Предоставляет способ обхода всех вершин иерархической структуры данных (например, древовидной).

Шаблоны параллельного программирования

Используются для более эффективного написания многопоточных программ, и предоставляет готовые решения проблем синхронизации.
Активный объект (Active Object) — Служит для отделения потока выполнения метода от потока, в котором он был вызван. Использует шаблоны асинхронный вызов методов и планировщик.
Уклонитель (Balking) — Служит для выполнения действия над объектом только тогда, когда тот находится в корректном состоянии.
Привязка свойств (Binding properties) — Комбинирует несколько наблюдателей для обеспечения синхронизации свойств в различных объектах
Обмен сообщениями (Messaging design pattern (MDP)) — Позволяет компонентам и приложениям обмениваться информацией (сообщениями).
Блокировка с двойной проверкой (Double-checked locking) — Предназначен для уменьшения накладных расходов, связанных с получением блокировки.
Ассинхронные события (Event-based asynchronous) — Адресные проблемы с Асинхронным паттерном, которые возникают в программах с несколькими потоками.
Охраняемая приостановка (Guarded suspension) — Используется для блокировки выполнения действия над объектом только тогда, когда тот находится в корректном состоянии.
Полусинхронизация (Half-Sync/Half-Async) — пока нет данных про этот паттерн.
Лидеры (Leaders/followers) — пока нет данных про этот паттерн.
Замок (Lock) — Один поток блокирует ресурс для предотвращения доступа или изменения его другими потоками.
Монитор (Monitor object) — Объект, предназначенный для безопасного использования более чем одним потоком.
Реактор (Reactor) — Предназначен для синхронной передачи запросов сервису от одного или нескольких источников.
Блокировка чтение-запись (Read write lock) — Позволяет нескольким потокам одновременно считывать информацию из общего хранилища, но позволяя только одному потоку в текущий момент времени её изменять.
Планировщик (Scheduler) — Обеспечивает механизм реализации политики планирования, но при этом не зависящих ни от одной конкретной политики.
Пул потоков (Thread pool) — Предоставляет пул потоков для обработки заданий, представленных обычно в виде очереди.
Спецпотоковое хранилище (Thread-specific storage) — Служит для предоставления различных глобальных переменных для разных потоков.
Однопоточное выполнение (Single thread execution) — Препятствует конкурентному вызову метода, тем самым запрещая параллельное выполнение этого метода.
Кооперативный паттерн (Cooperative pattern) — Обеспечивает механизм безопасной остановки потоков исполнения, используя общий флаг для сигнализирования прекращения работы потоков.

Шаблоны архитектуры системы

Model-View-Controller (MVC) — Модель-представление-контроллер.
Model-View-Presenter
Model-View-View Model
Presentation-Abstraction-Control
Naked objects
Hierarchical Model–View–Controller

Enterprise шаблоны

Active Record - способ доступа к данным реляционных баз данных в объектно-ориентированном программировании.
Business Delegate
Composite Entity/Составная Сущность
Composite View
DAO (Data Access Object) Объект Доступа к Данным
Dispatcher View
Front Controller
Intercepting Filter
Registry
Service Activator
Service Locator/Локатор Службы
Service to Worker
Session Facade/Фасад Сессии
Transfer Object Assembler
Transfer Object/Объект Перемещения
Value List Handler/Обработчик Списка Значений
View Helper
Unit of Work

Другие типы шаблонов

Также на сегодняшний день существует ряд других шаблонов.
Хранилище (Repository)
Carrier Rider Mapper описывают предоставление доступа к хранимой информации.
Аналитические шаблоны описывают основной подход для составления требований для программного обеспечения (requirement analysis) до начала самого процесса программной разработки
Коммуникационные шаблоны описывают процесс общения между отдельными участниками/сотрудниками организации
Организационные шаблоны описывают организационную иерархию предприятия/фирмы
Антипаттерны (Anti-Design-Patterns) описывают, как не следует поступать при разработке программ, показывая характерные ошибки в дизайне и в реализации

evgenyl 22 января 2012 в 21:18

Паттерны ООП в метафорах

  • Программирование

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

Что же такое вообще паттерн в ООП?
Паттерн (от англ. Pattern) - образец, шаблон.
Представьте, что вы хотите сделать новый автомобиль, но вы никогда этим не занимались. Сколько колес и почему вы спроектируете для него? Сейчас вы уже скорее всего скажете что 4, однако почему не 3, 5, 10, 20? Потому-что практикой использования уже было выяснено, что обычные автомобили лучше всего делать на 4-х колесах - это шаблон проектирования сформированный временем. Именно такому же подходу и служат паттерны в ООП и вы не столкнетесь с ними в разработке до тех пор, пока вам не потребуется «сделать автомобиль». Однако иногда случается так, что вы создаете «трицикл», и только потом, набив несколько шишек с его устойчивость и неудачным вписыванием в колею на дороге, узнаете что существует паттерн «автомобиль», который значительно упростил бы вам жизнь, знай вы про него ранее.

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

Порождающие паттерны

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

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

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

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

Примечание:
«Реестр» нередко является «одиночкой», однако это не всегда должно быть именно так. Например мы можем заводить в бухгалтерии несколько журналов, в одном работники от «А» до «М», в другом от «Н» до «Я». Каждый такой журнал будет «реестром», но не «одиночкой», потому как журналов уже 2. Хотя нередко «реестр» служит именно для хранения «одиночек».
Сам паттерн «реестр» не являтся «порождающим паттерном» в полном смысле этого термина, однако его удобно рассматривать именно во взаимосвязи с ними.

Multiton (пул «одиночек»)
Как понятно из названия паттерна, это по своей сути «реестр» содержащий несколько «одиночек», каждый из которых имеет своё «имя» по которому к нему можно получить доступ.
Object pool (пул объектов)
По аналогии с «пулом одиночек» данный паттерн также позволяет хранить уже готовые объекты, однако они не обязаны быть «одиночками».
Factory (фабрика)
Суть паттерна практически полностью описывается его названием. Когда вам требуется получать какие-то объекты, например пакеты сока, вам совершенно не нужно знать как их делают на фабрике. Вы просто говорите «сделайте мне пакет апельсинового сока», а «фабрика» возвращает вам требуемый пакет. Как? Всё это решает сама фабрика, например «копирует» уже существующий эталон. Основное предназначение «фабрики» в том, чтобы можно было при необходимости изменять процесс «появления» пакета сока, а самому потребителю ничего об этом не нужно было сообщать, чтобы он запрашивал его как и прежде.
Как правило, одна фабрика занимается «производством» только одного рода «продуктов». Не рекомендуется «фабрику соков» создавать с учетом производства автомобильных покрышек. Как и в жизни, паттерн «фабрика» часто создается «одиночкой».
Builder (строитель)
Данный паттерн очень тесно переплетается с паттерном «фабрики». Основное различие заключается в том, что «строитель» внутри себя, как правило, содержит все сложные операции по созданию объекта (пакета сока). Вы говорите «хочу сока», а строитель запускает уже целую цепочку различных операций (создание пакета, печать на нем изображений, заправка в него сока, учет того сколько пакетов было создано и т.п.). Если вам потребуется другой сок, например ананасовый, вы точно также говорите только то, что вам нужно, а «строитель» уже позаботится обо всем остальном (какие-то процессы повторит, какие-то сделает заново и т.п.). В свою очередь процессы в «строителе» можно легко менять (например изменить рисунок на упаковке), однако потребителю сока этого знать не требуется, он также будет легко получать требуемый ему пакет сока по тому же запросу.

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

Prototype (прототип)
Данный паттерн чем-то напоминает «фабрику», он также служит для создания объектов, однако с немного другим подходом. Представьте что у вас есть пустой пакет (из под сока), а вам нужен полный с апельсиновым соком. Вы «говорите» пакету «Хочу пакет апельсинового сока», он в свою очередь создает свою копию и заполняет ее соком, который вы попросили. Немного «сказочный пример», но в программировании часто так и бывает. В данном случае пустой пакет и является «прототипом», и в зависимости от того что вам требуется, он создает на своей основе требуемые вами объекты (пакеты сока).
Клонирование не обязательно должно производится на самом «пакете», это может быть и какой-то другой «объект», главное лишь что данный «прототип» позволяет получать его экземпляры.
Factory method (фабричный метод)
Данный паттерн довольно сложно объяснить в метафорах, но всё же попробую.
Ключевой сложностью объяснения данного паттерна является то, что это «метод», поэтому метафора метода будет использовано как действие, то есть например слово «Хочу!». Соответственно, паттерн описывает то, как должно выполнятся это «Хочу!».
Допустим ваша фабрика производит пакеты с разными соками. Теоретически мы можем на каждый вид сока делать свою производственную линию, но это не эффективно. Удобнее сделать одну линию по производству пакетов-основ, а разделение ввести только на этапе заливки сока, который мы можем определять просто по названию сока. Однако откуда взять название?
Для этого мы создаем основной отдел по производству пакетов-основ и предупреждаем все под-отделы, что они должны производить нужный пакет с соком про простому «Хочу!» (т.е. каждый под-отдел должен реализовать паттерн «фабричный метод»). Поэтому каждый под-отдел заведует только своим типом сока и реагирует на слово «Хочу!».
Таким образом если нам потребуется пакет апельсинового сока, то мы просто скажем отделу по производству апельсинового сока «Хочу!», а он в свою очередь скажет основному отделу по созданию пакетов сока, «Сделай ка свой обычный пакет и вот сок, который туда нужно залить».

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

Lazy initialization (отложенная инициализация)
Иногда требуется что-то иметь под рукой, на всякий случай, но не всегда хочется прилагать каждый раз усилия, чтобы это каждый раз получать/создавать. Для таких случаев используется паттерн «отложенная инициализация». Допустим вы работаете в бухгалтерии и для каждого сотрудника вы должны подготавливать «отчет о выплатах». Вы можете в начале каждого месяца делать этот отчет на всех сотрудников, но некоторые отчеты могут не понадобиться, и тогда скорее всего вы примените «отложенную инициализацию», то есть вы будете подготавливать этот отчет только тогда, когда он будет запрошен начальством (вышестоящим объектом), однако начальство по сути в каждый момент времени может сказать что у него этот отчет уже есть, однако готов он уже или нет, оно не знает и знать не должно. Как вы уже поняли, данный паттерн служит для оптимизации ресурсов.
Dependency injection (внедрение зависимости)
Внедрение зависимости позволяет переложить часть ответственности за какой-то функционал на другие объекты. Например если нам требуется нанять новый персонал, то мы можем не создавать свой отдел кадров, а внедрить зависимость от компании по подбору персонала, которая свою очередь по первому нашему требованию «нам нужен человек», будет либо сама работать как отдел кадров, либо же найдет другую компанию (при помощи «локатора служб»), которая предоставит данные услуги.
«Внедрение зависимости» позволяет перекладывать и взаимозаменять отдельные части компании без потери общей функциональности.
Service Locator (локатор служб)
автор:
«Локатор служб» является методом реализации «внедрения зависимости». Он возвращает разные типы объектов (компаний) в зависимости от кода инициализации. Пускай задача стоит доставить наш пакет сока, созданный строителем, фабрикой или ещё чем, куда захотел покупатель. Мы спрашиваем у локатора «дай нам службу доставки», и он нам соединяет на со службой доставки по номеру телефона, который директор ему дал (потому что получает откат они нам дают скидку как постоянным клиентам), а мы уже просим службу доставить сок по нужному адресу. Сегодня одна служба, а завтра может быть другая. Нам без разницы какая это конкретно служба, решение принимает директор и сообщает об этом локатору служб, нам важно знать лишь что они могут доставлять то, что мы им скажем туда, куда скажем, то есть службы реализуют интерфейс «Доставить <предмет> на <адрес>».

Структурирующие паттерны

Данные паттерны помогают внести порядок и научить разные объекты более правильно взаимодействовать друг с другом.
Adapter или wrapper (адаптер, обертка)
Данный паттерн полностью соответствует своему названию. Чтобы заставить работать «советскую» вилку через евро-розетку требуется переходник. Именно это и делает «адаптер», служит промежуточным объектом между двумя другими, которые не могут работать напрямую друг с другом.
Bridge (мост)
Представим ситуацию, когда вам требуется работать на разных автомобилях, однако садясь в новый автомобиль вам уже желательно знать как им управлять. Таким образом вы сталкиваетесь с паттерном «мост». С одной стороны вы имеете множество различных автомобилей (разные модели и марки), но среди все них есть общая абстракция (интерфейс) ввиде руля, педалей, коробки передач и так далее. Таким образом мы задаем как-бы правила изготовления автомобилей по которым мы можем создавать любые их виды, но за счет сохранения общих правил взаимодействия с ними, мы можем одинаково управлять каждым из них. «Мостом» в данном случае является пара двух «объектов»: конкретного автомобиля и правил взаимодействия с этим (и любым другим) автомобилем.
Composite (компоновщик)
Довольно интересный паттерн суть которого заключается в минимизации различий в управлении как группами объектов так и индивидуальными объектами. Для примера можно рассмотреть управление солдатами в строю. Существует строевой устав, который определяет как управлять строем и согласно этого устава абсолютно не важно кому отдается приказ (например «шагом марш») одному солдату или целому взводу. Соответственно в устав (если его в чистом виде считать паттерном «компоновщик») нельзя включить команду, которую может исполнить только один солдат, но не может исполнить группа, или наоборот.
Decorator (декоратор, оформитель)
Как понятно из названия, данный паттерн чаще всего используется для расширения исходного объекта до требуемого вида. Например мы условно можем считать «декоратором» человека с кистью и красной краской. Таким образом, какой бы объект (или определенный тип объектов) мы не передали в руки «декоратору», на выходе мы будем получать красные объекты.
Facade (фасад)
Паттерн «фасад» используется для того, чтобы делать сложные вещи простыми. Возьмем для примера автомобиль. Представьте, если бы управление автомобилем происходило немного по-другому: нажать одну кнопку чтобы подать питание с аккумулятора, другую чтобы подать питание на инжектор, третью чтобы включить генератор, четвертую чтобы зажечь ламочку на панели и так далее. Всё это было бы очень сложно. Для этого такие сложные наборы действий заменяются более простыми и комплексные как «повернуть ключ зажигания». В данном случае поворот ключа зажигания и будет тем самым «фасадом» для всего обилия внутренних действий автомобиля.
Front controller (единая точка входа)
Если проводить аналогии с реальными миром, то «единая точка входа» это то, через что вы сейчас читаете данную статью (например броузер). Она служит «единой точкой входа» для всего интернет пространства. То есть вы используете один интерфейс (броузер) для получения доступа к разным объектам большой системы (сайтам в интернете). Данный паттерн в целом сильно похож на «фасад».
Flyweight (приспособленец)
Самым лучшим примером (который я смог найти в реальной жизни) для метафорического сравнения паттерна «приспособленец» является театральная постановка. Представьте что нам требуется поставить пьесу. Однако по сценарию в этой пьесе задействованы несколько десятков людей, которые по своей сути выполняют одинаковые действия, например участвуют в массовках различных сцен в разные промежутки времени, но между ними всё же есть какие-то различия (например костюмы). Нам бы стоило огромных денег нанимать для каждой роли отдельного актера, поэтому мы используем паттерн «приспособленец». Мы создадим все нужные нам костюмы, но для каждой массовки будем переодевать небольшую группу актеров в требуемые для этой сцены костюмы. В результате мы имеем возможность ценой малых ресурсов создавать видимость управления большим количеством казалось бы разных объектов.
Proxy или surrogate (прокси, заместитель, суррогат)
Данный паттерн позволяет создавать какие-либо специальные механизмы доступа к объекту, что чаще всего направлено именно на улучшение производительности отдельных частей программы. В реальной жизни можно привести следующий пример: сотрудникам одного из подразделений фирмы регулярно требуется получать информацию о том, какого числа бухгалтерия планирует выплатить зарплату. С одной стороны каждый из них может индивидуально и регулярно ездить в бухгалтерию для выяснения этого вопроса (полагаю такая ситуация нередко встречается во многих организациях). С другой стороны, при приближении планируемой даты подразделение может выбрать одного человека, который будет выяснять эту информацию у бухгалтерии, а в последствии уже все в подразделении могут выяснить эту информацию у него (что значительно быстрее). Вот именно этот человек и будет реализованным «прокси» паттерном, который будет предоставлять специальный механизм доступа к информации из бухгалтерии.

Паттерны поведения

Эта группа паттернов позволяет структурировать подходы к обработке поведения и взаимодействия объектов. Проще говоря, как должны проходить процессы в которых существует несколько вариантов протекания событий.
Chain of responsibility (цепочка обязанностей)
Самым простым примером цепочки обязанностей можно считать получение какого-либо официального документа. Например вам требуется получить справку со счета из банка. Так или иначе, вы должны эту справку получить, однако кто именно ее должен вам дать - пока не ясно. Вы приходите в местное отделение банка, вам говорят что «мы сейчас заняты, идите в другое отделение», дальше вы идете в другое, там вам отвечают «мы этим не занимаемся», вы идете в региональное отделение и там получаете нужную справку. Таким образом паттерн реализует «цепочку обязанностей» отдельные объекты которой (отделения банка) должны обработать ваш запрос. Соответственно ваш запрос может быть обработан в первом же отделении, или же в нескольких, в зависимости от самого запроса и обрабатывающих объектов.
Command или action (команда, действие)
Паттерн «команда» очень похож в реальной жизни на кнопки выключателей света в наших квартирах и домах. Каждый выключатель по своей сути делает одно простое действие - разъединяет или соединяет два провода, однако что стоит за этими проводами выключателю не известно. Что подключат, то и произойдет. Точно также действует и паттерн «команда». Он лишь определяет общие правила для объектов (устройств), в виде соединения двух проводов для выполнения команды, а что именно будет выполнено уже определяет само устройство (объект).
Таким образом мы можем включать одним типом выключателей как свет в комнате, так и пылесос.
Interpreter (интерпретатор)
Сравнить данный паттерн можно с тем, как вы закладываете часто используемые действия в сокращенный набор слов, чтобы сам «интерпретатор» потом превратил этот набор в более комплексные осмысленные действия. По сути каждый человек постоянно является «интерпретатором». Хотите провести жизненный эксперимент? Если из дома выходит кто-то из вашей семьи (муж, жена, ребенок), скажите ему простой набор слов «Литр молока, половинку белого, 200 грамм творога». По сути вы ничего особенного не сказали, лишь перечислили набор продуктов, однако велик шанс того, что «интерпретатор» транслирует это в команду «зайди по дороге в продуктовый магазин и купи следующее … и принеси это домой». Паттерн «интерпретатор» призван сократить часто исполняемые действия в более короткое их описание.
Iterator (итератор, указатель)
Все помнят школьное «на первый второй рассчитайся!»? Вот именно в этот момент шеренга вашего класса и являлась реализацией паттерна «итератор», хотя в программировании это конечно более функциональное понятие, но суть примерно та же. «Итератор» предоставляет правила доступа к списку каких-либо объектов независимо от того, что это за объекты. То есть не важно какой именно класс построен и из каких учеников, должны быть общие правила подсчета и обращения как каждому ученику по списку, вроде «13-ый, выйти из строя». Нередко паттерн «итератор» используется для доступа к «реестру». Ссылки, которые вы видите на многих сайтах для переходов по страницам, вроде «следующая», «предыдущая», «в начало» и т.п. по своей сути также являются доступом «итератору» который отвечает за страницы сайта.
Mediator (посредник)
Вспомним пример из паттерна «одиночка». Так вот телефонная станция в том примере по сути также являлась паттерном «посредник», то есть обеспечивала взаимодействие группы объектов без необходимости обеспечения связи каждого объекта друг с другом.
Однако дополнительной ответственность этого «паттерна» является также управление этой группой через «посредника». То есть если мы возьмем пример с армейским строем, то медиатором будет командир отделения, то есть нам нет необходимости взаимодействовать с каждым солдатом в отдельности, достаточно отдавать приказания лишь командиру отделения, а он уже сам решит какие действия должны быть выполнены внутри его отделения.
Memento (хранитель)
Никогда не просили друга с сотовым телефоном на время запомнить (записать себе) тот номер, что диктуют вам по телефону, потому что вы не можете его запомнить сами (телефон занят)? В этот момент ваш друг реализовывал паттерн «хранитель». Он служит для тех случаев, когда какому-либо объекту требуется сохранить своё состояние (состояние знания номера) в другом объекте (вашем друге), и при необходимости его потом восстановить (спросить у друга номера и тем самым восстановить состояние когда вы его знали). Также уместен аналог с тем, как в играх работает сохранение. Файл «сейва» как раз и будет тем самым паттерном «хранитель».
Observer или Listener (наблюдатель, слушатель)
Очень распространенный паттерн в реальной жизни. Например если вы подписались на какую-либо email (или смс) рассылку, то ваш email (или номер сотового телефона) начинает реализовывать паттерн «наблюдатель». Как только вы подписываетесь на событие (например новая статья или сообщение), всем кто подписан на это событие (наблюдателям) будет выслано уведомление, а они уже в свою очередь могут выбрать как на это сообщение реагировать.
Blackboard (доска объявлений)
Данный паттерн служит для обеспечения взаимодействия между большим количеством объектов. Он является расширением паттерна «наблюдатель» и позволяет централизованно обслуживать как «наблюдателей», так и «создателей событий». В аналогии подпиской на email уведомления, это будет сам сайт подписки, который обслуживает множество подписчиков и тех, кто для них создает информацию (сообщения).
Servant (слуга)
Как следует из названия, данный паттерн служит для предоставления группе объектов какого-либо общего функционала. Например телефонная станция является для жителей города паттерном «слуга» если речь заходит о том, как узнать точное время (набрать номер 100).
State (состояние)
В реальной жизни каждый человек может прибывать в разных состояниях. Точно также порой требуется чтобы объекты в программе вели себя по разному в зависимости от каких-либо их внутренних состояний. По аналогии с реальной жизнью можно например привести следующий пример:
Если вы устали то на фразу «Сходи в магазин» вы будете выдавать «Не пойду», если вам нужно сходить в магазин (за пивом?), то на «Сходи в магазин» вы будете выдавать «Уже бегу!». Человек (объект) один и тот же, а поведение разное. Именно для этих целей и используют паттерн «состояние».
Strategy (стратегия)
Используется для выбора различных путей получения результата. Вспомним пример с получением прав. Человек, который будет реализовывать паттерн «стратегия» будет действовать следующим образом: вы говорите ему «Хочу права, денег мало» в ответ вы получите права через длительное время и с большой тратой ресурсов. Если вы скажите ему «Хочу права, денег много», то вы получите права очень быстро. Что именно делал этот человек вы понятия не имеете, но вы задаете начальные условия, а как себя вести уже решает он сам (сам выбирает стратегию).
Соответственно внутри «стратегии» хранятся различные способы поведения, и чтобы выбрать, ему нужны определенные параметры, в данном случае это объем денежных средств. Как устроена сама «стратегия» и какие алгоритмы внутри нее вам собственно знать и требуется.
Specification (спецификация, определение)
Паттерн спецификации позволяет описывать подходит ли данный объект нам на основе каких-либо критериев. Например мы имеем несколько контейнеров для погрузки на судно. Однако чтобы определить грузить контейнер или нет на определенное судно, нам нужно выбрать метод как это определять. Реализация такого метода и является паттерном «спецификация». В самом простом случае для каждого контейнера мы можем определить в паттерне «спецификация» совпадает ли страна назначения корабля со страной назначения контейнера. Соответственно мы один раз вводим правило «сравнить две страны назначения» и применяем его ко всем контейнерам для проверки.
Subsumption (категоризация)
Данный паттерн является прямым последователем паттерна «спецификация». Он позволяет распределять объекты по категориям на основе каких-либо условий. Соответственно по аналогии с примером кораблей и контейнеров, это категоризация по тому, какие контейнеры в какие страны направляются.
Visitor (посетитель)
Данный паттерн можно сравнить с прохождением обследования в больнице. Однако «посетителем» в терминах паттернов здесь будут сами врачи. Чтобы было понятнее: у нас есть больной которого требуется обследовать и полечить, но так как за разные обследования отвечают разные врачи, то мы просто присылаем к больному врачей в качестве «посетителей». Правило взаимодействия для больного очень простое «пригласите врача (посетителя) чтобы он сделал свою работу», а врач («посетитель») приходит, обследует и делает всё необходимое. Таким образом следуя простым правилам можно использовать врачей для разных больных по одним и тем же алгоритмам. Как уже было сказано, паттерном «посетитель» в данном случае является врач, который может одинаково обслуживать разные объекты (больных) если его позовут.
Single-serving visitor (одноразовый посетитель)
Является частным случаем использования паттерна «посетитель». Если в случае с обычным «посетителем» у нас есть врач которого мы можем отправить к разным больным (и при желании по несколько раз), то в данном паттерне можно привести аналогию, что мы нанимаем врача, отправляем его к одному больному и после обследования сразу увольняем.
Hierarchical visitor (иерархический посетитель)
Тот же самый паттерн «посетитель», однако в данном случае он отправляется к не одному больному, а в целую больницу и обходит там всех больных.

Заключение

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

Надеюсь вы нашли данный материал полезным для себя и благодарю за внимание.

Архитектура

Проектирование компьютерных программ

История

Польза

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

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

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

Критика

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

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

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

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

Для преодоления этих недостатков используется рефакторинг .

Основные типы шаблонов проектирования

Основные шаблоны (Fundamental)

  • Marker interface
  • Property Container

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

  • Factory Method/Фабричный метод , Virtual Constructor
  • Anonymous subroutine objects

Структурные шаблоны (Structural)

  • Proxy/Заместитель , Surrogate
  • Container
  • Extensibility
  • Pipes and filters
  • Private class data

Поведенческие шаблоны (Behavioral)

Шаблоны параллельного программирования (Concurrency)

  • Active Object
  • Balking
  • Guarded suspension
  • Half-Sync/Half-Async
  • Leaders/followers
  • Monitor Object
  • Reactor
  • Read write lock
  • Scheduler
  • Thread pool
  • Thread-Specific Storage
  • Single Thread Execution

MVC

  • Enterprise

    Unsorted

    • Property Container
    • Event Channel
    • Repository/Хранилище

    Другие типы шаблонов

    Также на сегодняшний день существует ряд других шаблонов:

    • Carrier Rider Mapper, предоставление доступа к хранимой информации
    • аналитические шаблоны, описывают основной подход для составления требований для программного обеспечения (requirement analysis) до начала самого процесса программной разработки
    • коммуникационные шаблоны, описывают процесс общения между отдельными участниками/сотрудниками организации
    • организационные шаблоны, описывают организационную иерархию предприятия/фирмы
    • Анти-паттерны (Anti-Design-Patterns) описывают как не следует поступать при разработке программ, показывая характерные ошибки в дизайне и в реализации.

    См. также

    • Обобщённое программирование
    • Ссылки

      • Ольга Дубина Обзор паттернов проектирования . - Обзор нескольких наиболее значительных монографий, посвященных паттернам проектирования информационных систем. Проверено 5 сентября 2006.
      • Portland Pattern Repository - список шаблонов проектирования на движке вики
      • mgrand’s book - сайт с описанием большого количества шаблонов проектирования
      • Resign Patterns - проломы проектно-дизориентированного проектирования (пародия на паттерны)
      • Eclipse’s Culture of Shipping (англ.) Erich Gamma

      Литература

      • Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес Приемы объектно-ориентированного проектирования. Паттерны проектирования = Design Patterns: Elements of Reusable Object-Oriented Software. - СПб: «Питер» , 2007. - С. 366. - ISBN 978-5-469-01136-1 (также ISBN 5-272-00355-1)
      • Крэг Ларман Применение UML 2.0 и шаблонов проектирования = Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development. - М.: «Вильямс» , 2006. - С. 736. - ISBN 0-13-148906-2
      • Мартин Фаулер Архитектура корпоративных программных приложений = Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series). - М.: «Вильямс» , 2007. - С. 544. - ISBN 0-321-12742-0
      • Джошуа Кериевски Рефакторинг с использованием шаблонов (паттернов проектирования) = Refactoring to Patterns (Addison-Wesley Signature Series). - М.: «Вильямс» , 2006. - С. 400. - ISBN 0-321-21335-1
      • Скотт В. Эмблер, Прамодкумар Дж. Садаладж Рефакторинг баз данных: эволюционное проектирование = Refactoring Databases: Evolutionary Database Design (Addison-Wesley Signature Series). - М.: «Вильямс» , 2007. - С. 368. - ISBN 0-321-29353-3

      Wikimedia Foundation . 2010 .

  • Паттерсон, Джемс
  • Паттерсон, Персиваль

Смотреть что такое "Паттерны проектирования" в других словарях:

    Шаблон проектирования - У этого термина существуют и другие значения, см. Паттерн. В разработке программного обеспечения, шаблон проектирования или паттерн (англ. design pattern) повторимая архитектурная конструкция, представляющая собой решение проблемы… … Википедия

    Шаблоны проектирования - (паттерн, англ. design pattern) это многократно применяемая архитектурная конструкция, предоставляющая решение общей проблемы проектирования в рамках конкретного контекста и описывающая значимость этого решения. Паттерн не является законченным… … Википедия

    Шаблоны проектирования GRASP - GRASP (англ. General Responsibility Assignment Software Patterns (общие образцы распределения обязанностей)) паттерны, используемые в объектно ориентированном проектировании для решения общих задач по назначению обязанностей классам и объектам. В … Википедия

Похожие статьи