Поведенческие шаблоны проектирования определяют общие закономерности связей между объектами, реализующими данные паттерны. Следование этим шаблонам уменьшает связность системы и оптимизирует взаимодействие между объектами, что приводит к улучшению гибкости, надежности и сопровождаемости программного продукта.
Поведенческие шаблоны, как и все паттерны проектирования в целом, составляют собой библиотеку практических приемов, подкрепленных теоретическим базисом сферы информационных технологий. Они не являются абстрактным знанием, а служат утилитарным целям и могут приносить достаточную ценность при их последовательном, постоянном и грамотном применении.
В поведенческих шаблонах, как и в смежных им структурных шаблонах, используется наследование, в качестве инструмента определения поведения для различных классов, и композиция, как уравнитель и распределитель выполняемых ими обязанностей.
Некоторые из тех, что мы рассмотрим далее, описывают, как с помощью взаимодействия наборы равноправных объектов работают над заданием, которое они не могут выполнить по отдельности. Ключевым моментом в таком подходе является осведомленность объектов о существовании друг друга. "Коллеги" должны хранить ссылки друг на друга, но это усиливает степень связанности системы. При высокой связанности каждому объекту пришлось бы иметь информацию обо всех остальных.
Поведенческие шаблоны проектирования решают задачи, обозначенные выше, и оптимизируют общую производительность системы.
Когда необходимо разрабатывать и поддерживать одну и ту же часто встречающуюся, подверженную изменениям задачу, это приводит к тому, что сопровождать логику приложения с большим количеством изменений затруднительно.
В этом случае целесообразно разработать шаблон "Интерпретатор", который решает данную задачу.
"Интерпретатор" (англ. Interpreter) – поведенческий шаблон проектирования, решающий часто встречающуюся, но подверженную изменениям задачу. Также известен как Little (Small) Language.
Как уже было обозначено, данный шаблон проектирования применяется для решения задач часто повторяющихся операций. Несмотря на то, что реализация этого паттерна требует понимания теории формальных языков и грамматик, он не сложен в восприятии и дальнейшей трактовки. Для его разработки потребуются следующие участники:
Жизненной аналогией этого шаблона является мясорубка, которая способна по определенным правилам преобразовывать небольшой входной набор кусков различного мяса к определенному виду фарша (разного состава). Такая мясорубка является достаточно надежным и универсальным инструментом, если на вход ей не подавать что-то совсем плотное и жесткое.
(рис 6.2.1) Шаблон "Интерпретатор"
В тех случаях, когда требуется, чтобы сложный составной объект, например список, предоставлял доступ к своим элементам (объектам), не раскрывая их внутреннюю структуру, причем перебирать список требуется по-разному в зависимости от задачи, применяется шаблон "Итератор".
В качестве основного назначения паттерна следует выделить:
Таким образом, данный паттерн используется, когда необходим механизм "абстрактного" обхода различных структур данных так, чтобы были определены алгоритмы, способные взаимодействовать со структурами прозрачно. Если раскрыть тему реализации и возможностей этого шаблона, то следует сказать о том, что любой составной объект, такой как список, должен предоставлять способ доступа к его элементам без раскрытия своей внутренней структуры. Иногда это является не просто вариантом использования структуры данных, а нужно перебирать элементы списка различными способами, в зависимости от конкретной задачи, а иногда нужно иметь несколько активных обходов одного списка одновременно. Идеальным решением в таком случае является единый интерфейс для обхода разных типов составных объектов. Именно подобная функциональность работы с комплексными объектами осуществляется с помощью паттерна "Итератор". Ключевая идея состоит в том, чтобы ответственность за доступ и обход переместить из составного объекта на сам итератор, который будет определять стандартный протокол обхода.
Алгоритм реализации данного шаблона предписывает следующие стадии:
Таким образом, из коллекции данных "выносится" функциональность обхода элементов и ей придается статус объекта. Это приводит к тому, что:
Каждому классу рекомендуется иметь итератор. В том случае, когда потребуется дополнительная функциональность, если "Итератор" первоначально был предусмотрен, то можно будет добавить необходимую функциональность достаточно простои быстро, без изменений первоначального кода программы.
Аналогией этого шаблона является алфавитный библиотечный указатель, который предоставляет своему потребителю возможность быстро изучить структуру его элементов и при необходимости получить к ним доступ, но не предоставляет сами элементы, а только ссылки на них.
(рис 6.2.2) Шаблон "Итератор"
Когда необходимо послать объекту запрос, не зная о том, выполнение какой операции запрошено и кто будет получателем, целесообразно применять шаблон "Команда". Основополагающая идея данного шаблона заключается в использовании единого интерфейса для описания всех типов операций, которые можно производить с системой. Для добавления в систему поддержки новой операции достаточно реализовать требуемый интерфейс. Каждая операция представляется самостоятельным объектом, инкапсулирующим некоторый набор дополнительных свойств.
В этом шаблоне алгоритм представления бизнес-логики организован в виде последовательности процедур, которые управляют каждая своим запросом. Любое приложение можно представить в виде набора транзакций. Какие-то из них выбирают данные, какие-то – меняют. Каждое взаимодействие пользователя и системы содержит определенный набор действий. Паттерн "Команда" организует всю используемую логику в одну "над" -процедуру, работая сданными напрямую или через тонкую обертку.
При реализации шаблона "Команда" следует обратить внимание на следующие моменты:
Получатель должен предоставить операции, позволяющие команде вернуться в исходное состояние. Для поддержки всего одного уровня отмены приложению достаточно сохранять только последнюю выполненную команду. Если же нужны многоуровневые отмена и повтор операций, то придется вести список истории выполненных команд. Максимальная длина этого списка определяет число уровней отмены и повтора. Проход по списку в обратном направлении и откат результатов всех встретившихся по пути команд отменяет их действие. Проход в прямом направлении и выполнение встретившихся команд приводит к повтору выполнения действий.
Известно большое количество задач, где подход к их решению задан с помощью шаблона "Команда":
Перечислять такие задачи можно бесконечно, важно понять, что шаблон "Команда"– один из самых распространенных шаблонов проектирования. Аналогией данного шаблона является полет на борту самолета. После того как самолет взлетел, есть только два возможных дальнейших пути–попасть в точку назначения или вернуться в точку вылета. Все остальные действия, которые проходят по ходу полета,не рассматриваются в отрыве от самого перелета и являются необходимыми составляющими для его завершения.
В том случае, когда информационная система состоит из множества различных классов и взаимодействующих объектов, которые находятся в согласованных состояниях между собой, когда необходимо сохранять гибкость системы или избегать монолитности путем повышения возможности переиспользования существующих классов, принято использовать шаблон проектирования "Наблюдатель".
Если попробовать описать суть данного паттерна в виде метафоры, то наиболее удачным является сравнение с приходящей к вам рассылкой. В этом случае устройство, на которое вы получаете рассылку (телефон, компьютер и пр.), реализует шаблон "Наблюдатель". То есть:
Таким образом, этот шаблон определяет зависимость "один-ко-многим" между объектами так, что при изменении состояния одного объекта все зависящие от него объекты уведомляются и обновляются автоматически.
Объект представляет основную, достаточно независимую абстракцию, "наблюдатель" является зависимой абстракцией. Объект извещает наблюдателей о своем изменении, на что каждый наблюдатель будет реагировать по-своему, может запросить дополнительную информацию от объекта, а может проигнорировать изменившееся состояние.
Шаблон "Наблюдатель" можно охарактеризовать следующими отличительными чертами:
Для реализации шаблона наблюдатель необходимо:
В качестве основных достоинств применения шаблона "Наблюдатель" являются:
Недостатками являются:
"Не разговаривайте с неизвестным" – один из самых неизвестных шаблонов проектирования, задача которого состоит в снижении монолитности и повышении гибкости системы за счет снижения зависимости объекта от косвенных компонентов системы, о которых ему напрямую ничего не известно.
При его реализации следует избегать решений, предполагающих взаимодействие с удаленными непрямыми объектами ("незнакомцами"). Во многом этот шаблон воспринимается как частный случай уже рассмотренного нами ранее паттерна "Устойчивый к изменениям".
Что касается явных недостатков применения этого шаблона, стоит отметить, что прямым объектам потребуются новые операции, поддерживающие реализацию данного шаблона.
В конечном итоге, использование шаблона "Не разговаривайте с неизвестным" позволит обеспечить устойчивость системы к изменению структуры отдельных объектов.
Применение шаблона "Посетитель" оправданно в ситуациях, когда над объектом конкретной структуры необходимо определить новую операцию, но при этом не требуется изменять исходный класс.
Компонент, использующий данный паттерн:
Исходя из описания реализации шаблона "Посетитель", обоснованно предположить, что его логично использовать, если в структуре присутствуют объекты многих классов с различными интерфейсами, и необходимо выполнить над ними операции, зависящие от конкретных классов, или если классы, устанавливающие структуру объектов, изменяются редко, но новые операции над этой структурой добавляются часто.
Главными преимуществами применения этого паттерна являются следующие:
При этом в качестве основного недостатка выделим то, что затруднено добавление новых классов к системным "элементам", поскольку требуется объявление новой абстрактной операции в классе "Посетитель".
В качестве аналогии этого шаблона можно выделить работника, приходящего на определенное время для выполнения узкоспециализированных операций (няня, уборщица и т.д.). Работник приходит для выполнения конкретных действий, выполнение которых отвлекает хозяев от их обыденной жизни, и уходит, получив конкретное возмещение за проделанный труд. Конечно, можно переложить на него и дополнительные обязанности, но это потребует от хозяев вложения дополнительных средств.
Если стоит необходимость проектирования и реализации системы или ее модуля с использованием существующих компонентов, на уже реализованные связи между этими компонентами можно характеризовать феноменом "Спагетти-кода", стоит задуматься о применении шаблона проектирования "Посредник".
"Спагетти-код"– низкоструктурированная, запутанная и трудная для понимания программа. "Спагетти-код" назван так, потому что ход выполнения программы похож на миску спагетти–извилистый и запутанный.
Шаблон "Посредник" применяется в том случае, когда необходимо обеспечить взаимодействие множества объектов, сформировав при этом слабую связанность и избавив объекты от необходимости явно ссылаться друг на друга.
"Посредник" используется в системах, где взаимодействие между компонентами может быть весьма сложным, но хорошо определенным. Особенно актуальным является внедрение этого паттерна, если есть предпосылки к тому, что связи между модулями будут постоянно расти и усложняться. Шаблон "Посредник" можно сравнить с уже рассмотренным ранее архитектурным шаблоном "Диспетчер". Они выполняют схожие функции, но обладают разными обязанностями.
Для реализации шаблона "Посредник" потребуется:
Шаблон "Посредник" определяет объект, управляющий набором взаимодействующих объектов. Слабая связанность достигается благодаря тому, что вместо непосредственного взаимодействия друг с другом коллеги общаются через объект-посредник.
Для того чтобы внедрение шаблона "Посредник" в программу было выполнено наиболее эффективным образом, необходимо предварительно:
Применение шаблона "Посредник" позволяет:
Недостатки же его использования следующие:
"Посредник" выполняет функцию организации взаимодействия между существующими элементами, которые выполняют свои обязанности, и новыми компонентами, в которых использование существующих элементов приносит дополнительную ценность программному продукту, выраженную, как правило, в экономии ресурсов на его реализацию.
В ситуациях, когда требуется варьировать поведение объекта в зависимости от его внутреннего состояния, используют шаблон проектирования cодноименным названием–"Состояние".
Состояние каждого объекта определяется его поведением и изменяется во время выполнения программы. Текущее состояние объекта запускает ряд функций, выполнение которых переводит объект в другие состояния. Но объекты, обладающие большим числом состояний, как правило, содержат сложные механизмы диверсификации и структуру кода. Преодоление этого недостатка решается за счет рассматриваемого паттерна.
Структура этого паттерна определяется следующим образом:
Реализацию паттерна "Состояние" можно организовать следующим способом:
Использование шаблона "Состояние" локализует зависящее от состояния поведение и делит его на части, соответствующие состояниям, переходы между состояниями становятся явными, а процесс работы с объектом – более прозрачным и понятным.
Реализация статусной модели похожа на ожидание возможности перехода у светофора. Когда загорается красный свет, все участники движения понимают, что настал момент, когда автомобилисты должны остановиться и пропустить пешеходов. Загоревшийся зеленый свет оповещает о том, что теперь пешеходы должны переходить дорогу.
(рис 6.2.8) Шаблон "Состояние"
В ситуациях, когда определенный класс содержит ряд схожих алгоритмов (способов сделать то или иное действие), как правило, эти алгоритмы приводят к одному и тому же результату, но могут отличаться по другим параметрам (время выполнения, потребление системных ресурсов и др.).В подобных ситуациях целесообразно использовать шаблон "Стратегия".
В основной идее данного шаблона лежит необходимость выделения семейства схожих алгоритмов и инкапсуляции каждого из них в собственный класс. После этого алгоритмы можно заменять прямо во время исполнения программы.
Для реализации данного шаблона потребуется:
Применение шаблона "Стратегия" позволяет сделать специализированные модули программного обеспечения более понятными, читаемыми и однозначными.
К основным преимуществам использования этого шаблона следует отнести следующие:
Если провести "жизненную" аналогию по применению этого шаблона, то уместным будет следующее сравнение:
(рис 6.2.9) Шаблон "Стратегия"
Когда необходимо зафиксировать поведение объекта для его последующей реализации, применяется шаблон "Хранитель".
Этот шаблон применяется, если требуется зафиксировать и вынести (не нарушая структуры программы) за пределы объекта его внутреннее состояние так, чтобы впоследствии можно было восстановить в нем объект.
Таким образом, не нарушая принципа инкапсуляции, шаблон "Хранитель" получает и сохраняет за пределами объекта его внутреннее состояние так, чтобы позже можно было восстановить объект в первоначальном состоянии.
Особенно актуально применение этого паттерна в ситуации, когда нужно восстановить объект обратно в прежнее состояние.
Для реализации данного шаблона обязательно должны быть определены 3 различных "участника":
Алгоритм выполнения шаблона "Хранитель" определяется следующим образом:
Основные недостатки и издержки использования этого шаблона проектирования связаны с объемом объекта "Хозяин". Если он слишком велик, то "Хранитель" должен копировать большой объем информации. Если структура программного продукта подразумевает частое использование шаблона "Хранитель", то требуются значительные системные ресурсы для поддержки производительности программного обеспечения.
Шаблон проектирования "Хранитель" фиксирует и сохраняет за пределами объекта "Хранителя" его внутреннее состояние так, чтобы позже этот объект можно было бы восстановить в таком же состоянии.
Этот шаблон используется в функциональности тех приложений, когда есть возможность отменить последнее действие и вернуть систему в предыдущее состояние.
Хорошей жизненной аналогией данного паттерна является коробка с паззлом, на передней части которой изображена картина в целом. Именно напоминание картины в целом –это "Хранитель" конечного состояния объекта.
В случаях, когда требуется эффективно, компактно, надежно реализовать обработку потока информации с потенциально большим количеством обработчиков, используется шаблон проектирования "Цепочка обязанностей".
В современных системах количество обработчиков во многом определяет оперативность выполнения системой ее функций, поэтому их количество, как правило, достаточно велико.
С одной стороны, все прозрачно и понятно–есть множество типов сообщений, есть множество обработчиков этих сообщений. Задача системы состоит в том, чтобы обрабатывать каждое сообщение в потоке ассоциированным с его конкретным типом обработчика.
Паттерн "Цепочка обязанностей" позволяет реализовать эффективный механизм увязывания типов сообщений и обработчиков.
Если в системе небольшое число обработчиков, то достаточно реализовать данный механизм на базе цикличной конструкции (if, case, whileи пр.). Однако по мере роста и развития систем появляются дополнительные значимые нюансы:
Основная идея этого шаблона заключается в организации конвейера из обработчиков, в котором каждый может либо обработать поступившее сообщение, либо делегировать обработку следующему в конвейере обработчику. Возможен еще вариант обработки и последующей передачи:
Шаблон "Цепочка обязанностей" позволяет:
Этот шаблон проектирования достаточно требователен к системным ресурсам. В частности, необходимо убедиться, что программа корректно "отлавливает" случаи необработанных запросов.
"Жизненным" примером этого шаблона является компьютерная сеть–большое количество обработчиков, узлов сети (компьютеров, серверов, маршрутизаторов) и еще большее количество типов сетевых запросов:
(рис 6.2.11) Шаблон "Цепочка обязанностей"
Когда имеются два разных, но в тоже время очень похожих компонента и требуется внести изменения в оба компонента, избежав при этом вредоносного дублирования кода, применяется паттерн "Шаблонный метод".
"Шаблонный метод" определяет основной алгоритм и позволяет подклассам изменить некоторые шаги этого алгоритма без изменения его общей структуры.
Для применения этого шаблона необходимо исследовать общий алгоритм и определить, какие его шаги и стадии являются стандартными, то есть общими, а какие должны определяться подклассами в зависимости от условий конкретной задачи. Создается абстрактный базовый класс, в котором реализован принцип общности и определения стандартных шагов. Если для некоторых шагов требуются различные реализации, то определяются "замещающие" методы:
"Шаблонный метод" широко применяется в каркасах приложений разработки программного обеспечения. Каждый каркас реализует неизменные части архитектуры в предметной области, а также определяет те части, которые могут или должны настраиваться для конкретного случая. Таким образом, каркас приложения становится "солнцем", а настройки являются "планетами".
Строители зданий используют паттерн "Шаблонный метод" при проектировании новых домов. Используются типовые, хорошо себя зарекомендовавшие планы, в которых модифицируются отдельные части, не влияющие на основные архитектурные компоненты.
Шаблон "Высокое зацепление" решает задачу управления сложностью программного обеспечения за счет регулирования степени зацепления системных классов между собой.
Понятия зацепления и связанности достаточно часто встречаются в профильной литературе, описывающей принципы современных программных продуктов. Принято считать, что каждая информационная система, спроектированная в соответствии с отраслевыми стандартами, должна удовлетворять принципам низкой связности и высокого зацепления ее внутренних модулей.
Стоит пояснить, что разница между связностью и зацеплением достаточно большая, но не совсем очевидная. Вкратце разницу понятий можно охарактеризовать следующим образом:
Элемент обладает высокой степенью зацепления, если его обязанности тесно связаны между собой, и он не выполняет огромных объемов работы. Класс с низкой степенью зацепления выполняет много разнородных функций или несвязанных между собой обязанностей.
Реализация шаблона "Высокое зацепление" позволяет легко модифицировать и сопровождать программное обеспечение, повышает возможность его повторного использования.
Мера связности модулей определяется количеством информации, которой располагает один модуль о природе другого. В свою очередь, мера зацепления модуля определяется степенью сфокусированности его обязанностей.
Принципы реализации высокого зацепления утверждают, что класс должен стараться выполнять как можно меньше неспецифичных для него задач и иметь вполне определенную область применения. Считается что связывание и зацепление –это "инь" и "янь" проектирования ПО. Некорректное связывание порождает неправильное зацепление, и наоборот.
В условиях, когда система должна отвечать за обработку большого количества входных системных событий, целесообразно использовать шаблон "Контроллер".
Суть реализации шаблона "Контроллер" состоит в определении обязанности по обработке системных сообщений, которые должны быть делегированы специальному классу или классам.
"Контроллер"– это объект, который отвечает за обработку системных событий и не относится к интерфейсу пользователя. "Контроллер" определяет методы выполнения системных операций.
Паттерн "Контроллер" призван решить наболевшую проблему разделения интерфейса и логики в интерактивном приложении.
Если вспомнить изученный ранее архитектурный шаблон MVC, то шаблон проектирования "Контроллер" отвечает за организацию компоненты, скрывающейся под символом "С":
Системный компонент, реализуемый по шаблону "Контроллер", должен удовлетворять следующим условиям:
Для различных экземпляров процесса обработки входных сообщений ("прецедентов") логично использовать разные контроллеры ("контроллеры прецедентов").Контроллеры не должны быть перегружены, иначе это приведет к ошибкам при отработке логики приложения.
Шаблон "Контроллер" является не объектом автоматизации предметной области, а искусственной конструкцией, которая выполняется в соответствии с четко определенными правилами.
"Контроллер" выполняет роль универсального и добросовестного постового, который следует общим правилам и не допускает возникновения заторов и пробок. Его задача –следить за выполнением установленного процесса и корректировать ход его исполнения в случаях, когда кто-то из участников дорожного движения вышел за рамки установленных правил.
Принцип полиморфизма является основополагающим для современной парадигмы объектно-ориентированного программирования. В контексте применения шаблонов проектирования паттерн "Полиморфизм" призван решать задачу обработки вариантов поведения системы на основе типа обрабатываемого сообщения или данных. Лучше всего эта задача решается с использованием полиморфных операций. Кроме того, при помощи шаблона "Полиморфизм" легко создавать подключаемые к системе компоненты. В итоге использование принципов полиморфизма позволяет получить следующие преимущества:
Но не следует злоупотреблять добавлением интерфейсов с применением принципа полиморфизма, если поведение внешней системы изучено не до конца. Это может привести к возникновению большого числа отложенных ошибок.
Что необходимо сделать для перераспределения обязанностей между объектами, чтобы обеспечить отсутствие прямого связывания, которое влияет на гибкость системы в целом?
Наиболее очевидным вариантом является делегирование обязанности обеспечения связи между службами или компонентами специализированному промежуточному объекту. Рассматриваемый шаблон "Перенаправление" разработан для решения задачи прямой связности.
Паттерн реализует низкую связность между классами, путем назначения обязанностей по их взаимодействию дополнительному объекту – посреднику.
В этой главе мы изучили поведенческие шаблоны проектирования. Эта группа шаблонов является логичным продолжением рассмотренных нами ранее структурных шаблонов, но их специфическое назначение связано с регламентацией поведения системных объектов, т.е. особенностей их функционирования.
Поведенческие шаблоны, с точки зрения вклада в архитектурное проектирование, являются связующим звеном между структурными, порождающими и архитектурными, интеграционными шаблонами.
Оптимальное использование поведенческих шаблонов позволит нивелировать недостатки неудачно спроектированного программного обеспечения, снизить отдельные, наиболее отрицательные или повысить удачные характеристики программного продукта.
Именно высокий уровень владения деталями реализации поведенческих паттернов поможет разработчику информационной системы оперативно устранить самые значимые недостатки отдельных компонентов информационной системы.
Поведенческие шаблоны проектирования определяют общие закономерности связей между объектами, реализующими данные паттерны. Следование этим шаблонам уменьшает связность системы и оптимизирует взаимодействие между объектами, что приводит к улучшению гибкости, надежности и сопровождаемости программного продукта.
Поведенческие шаблоны, как и все паттерны проектирования в целом, составляют собой библиотеку практических приемов, подкрепленных теоретическим базисом сферы информационных технологий. Они не являются абстрактным знанием, а служат утилитарным целям и могут приносить достаточную ценность при их последовательном, постоянном и грамотном применении.
В поведенческих шаблонах, как и в смежных им структурных шаблонах, используется наследование, в качестве инструмента определения поведения для различных классов, и композиция, как уравнитель и распределитель выполняемых ими обязанностей.
Некоторые из тех, что мы рассмотрим далее, описывают, как с помощью взаимодействия наборы равноправных объектов работают над заданием, которое они не могут выполнить по отдельности. Ключевым моментом в таком подходе является осведомленность объектов о существовании друг друга. "Коллеги" должны хранить ссылки друг на друга, но это усиливает степень связанности системы. При высокой связанности каждому объекту пришлось бы иметь информацию обо всех остальных.
Поведенческие шаблоны проектирования решают задачи, обозначенные выше, и оптимизируют общую производительность системы.
Когда необходимо разрабатывать и поддерживать одну и ту же часто встречающуюся, подверженную изменениям задачу, это приводит к тому, что сопровождать логику приложения с большим количеством изменений затруднительно.
В этом случае целесообразно разработать шаблон "Интерпретатор", который решает данную задачу.
"Интерпретатор" (англ. Interpreter) – поведенческий шаблон проектирования, решающий часто встречающуюся, но подверженную изменениям задачу. Также известен как Little (Small) Language.
Как уже было обозначено, данный шаблон проектирования применяется для решения задач часто повторяющихся операций. Несмотря на то, что реализация этого паттерна требует понимания теории формальных языков и грамматик, он не сложен в восприятии и дальнейшей трактовки. Для его разработки потребуются следующие участники:
Жизненной аналогией этого шаблона является мясорубка, которая способна по определенным правилам преобразовывать небольшой входной набор кусков различного мяса к определенному виду фарша (разного состава). Такая мясорубка является достаточно надежным и универсальным инструментом, если на вход ей не подавать что-то совсем плотное и жесткое.
(рис 6.2.1) Шаблон "Интерпретатор"
В тех случаях, когда требуется, чтобы сложный составной объект, например список, предоставлял доступ к своим элементам (объектам), не раскрывая их внутреннюю структуру, причем перебирать список требуется по-разному в зависимости от задачи, применяется шаблон "Итератор".
В качестве основного назначения паттерна следует выделить:
Таким образом, данный паттерн используется, когда необходим механизм "абстрактного" обхода различных структур данных так, чтобы были определены алгоритмы, способные взаимодействовать со структурами прозрачно. Если раскрыть тему реализации и возможностей этого шаблона, то следует сказать о том, что любой составной объект, такой как список, должен предоставлять способ доступа к его элементам без раскрытия своей внутренней структуры. Иногда это является не просто вариантом использования структуры данных, а нужно перебирать элементы списка различными способами, в зависимости от конкретной задачи, а иногда нужно иметь несколько активных обходов одного списка одновременно. Идеальным решением в таком случае является единый интерфейс для обхода разных типов составных объектов. Именно подобная функциональность работы с комплексными объектами осуществляется с помощью паттерна "Итератор". Ключевая идея состоит в том, чтобы ответственность за доступ и обход переместить из составного объекта на сам итератор, который будет определять стандартный протокол обхода.
Алгоритм реализации данного шаблона предписывает следующие стадии:
Таким образом, из коллекции данных "выносится" функциональность обхода элементов и ей придается статус объекта. Это приводит к тому, что:
Каждому классу рекомендуется иметь итератор. В том случае, когда потребуется дополнительная функциональность, если "Итератор" первоначально был предусмотрен, то можно будет добавить необходимую функциональность достаточно простои быстро, без изменений первоначального кода программы.
Аналогией этого шаблона является алфавитный библиотечный указатель, который предоставляет своему потребителю возможность быстро изучить структуру его элементов и при необходимости получить к ним доступ, но не предоставляет сами элементы, а только ссылки на них.
(рис 6.2.2) Шаблон "Итератор"
Когда необходимо послать объекту запрос, не зная о том, выполнение какой операции запрошено и кто будет получателем, целесообразно применять шаблон "Команда". Основополагающая идея данного шаблона заключается в использовании единого интерфейса для описания всех типов операций, которые можно производить с системой. Для добавления в систему поддержки новой операции достаточно реализовать требуемый интерфейс. Каждая операция представляется самостоятельным объектом, инкапсулирующим некоторый набор дополнительных свойств.
В этом шаблоне алгоритм представления бизнес-логики организован в виде последовательности процедур, которые управляют каждая своим запросом. Любое приложение можно представить в виде набора транзакций. Какие-то из них выбирают данные, какие-то – меняют. Каждое взаимодействие пользователя и системы содержит определенный набор действий. Паттерн "Команда" организует всю используемую логику в одну "над" -процедуру, работая сданными напрямую или через тонкую обертку.
При реализации шаблона "Команда" следует обратить внимание на следующие моменты:
Получатель должен предоставить операции, позволяющие команде вернуться в исходное состояние. Для поддержки всего одного уровня отмены приложению достаточно сохранять только последнюю выполненную команду. Если же нужны многоуровневые отмена и повтор операций, то придется вести список истории выполненных команд. Максимальная длина этого списка определяет число уровней отмены и повтора. Проход по списку в обратном направлении и откат результатов всех встретившихся по пути команд отменяет их действие. Проход в прямом направлении и выполнение встретившихся команд приводит к повтору выполнения действий.
Известно большое количество задач, где подход к их решению задан с помощью шаблона "Команда":
Перечислять такие задачи можно бесконечно, важно понять, что шаблон "Команда"– один из самых распространенных шаблонов проектирования. Аналогией данного шаблона является полет на борту самолета. После того как самолет взлетел, есть только два возможных дальнейших пути–попасть в точку назначения или вернуться в точку вылета. Все остальные действия, которые проходят по ходу полета,не рассматриваются в отрыве от самого перелета и являются необходимыми составляющими для его завершения.
В том случае, когда информационная система состоит из множества различных классов и взаимодействующих объектов, которые находятся в согласованных состояниях между собой, когда необходимо сохранять гибкость системы или избегать монолитности путем повышения возможности переиспользования существующих классов, принято использовать шаблон проектирования "Наблюдатель".
Если попробовать описать суть данного паттерна в виде метафоры, то наиболее удачным является сравнение с приходящей к вам рассылкой. В этом случае устройство, на которое вы получаете рассылку (телефон, компьютер и пр.), реализует шаблон "Наблюдатель". То есть:
Таким образом, этот шаблон определяет зависимость "один-ко-многим" между объектами так, что при изменении состояния одного объекта все зависящие от него объекты уведомляются и обновляются автоматически.
Объект представляет основную, достаточно независимую абстракцию, "наблюдатель" является зависимой абстракцией. Объект извещает наблюдателей о своем изменении, на что каждый наблюдатель будет реагировать по-своему, может запросить дополнительную информацию от объекта, а может проигнорировать изменившееся состояние.
Шаблон "Наблюдатель" можно охарактеризовать следующими отличительными чертами:
Для реализации шаблона наблюдатель необходимо:
В качестве основных достоинств применения шаблона "Наблюдатель" являются:
Недостатками являются:
"Не разговаривайте с неизвестным" – один из самых неизвестных шаблонов проектирования, задача которого состоит в снижении монолитности и повышении гибкости системы за счет снижения зависимости объекта от косвенных компонентов системы, о которых ему напрямую ничего не известно.
При его реализации следует избегать решений, предполагающих взаимодействие с удаленными непрямыми объектами ("незнакомцами"). Во многом этот шаблон воспринимается как частный случай уже рассмотренного нами ранее паттерна "Устойчивый к изменениям".
Что касается явных недостатков применения этого шаблона, стоит отметить, что прямым объектам потребуются новые операции, поддерживающие реализацию данного шаблона.
В конечном итоге, использование шаблона "Не разговаривайте с неизвестным" позволит обеспечить устойчивость системы к изменению структуры отдельных объектов.
Применение шаблона "Посетитель" оправданно в ситуациях, когда над объектом конкретной структуры необходимо определить новую операцию, но при этом не требуется изменять исходный класс.
Компонент, использующий данный паттерн:
Исходя из описания реализации шаблона "Посетитель", обоснованно предположить, что его логично использовать, если в структуре присутствуют объекты многих классов с различными интерфейсами, и необходимо выполнить над ними операции, зависящие от конкретных классов, или если классы, устанавливающие структуру объектов, изменяются редко, но новые операции над этой структурой добавляются часто.
Главными преимуществами применения этого паттерна являются следующие:
При этом в качестве основного недостатка выделим то, что затруднено добавление новых классов к системным "элементам", поскольку требуется объявление новой абстрактной операции в классе "Посетитель".
В качестве аналогии этого шаблона можно выделить работника, приходящего на определенное время для выполнения узкоспециализированных операций (няня, уборщица и т.д.). Работник приходит для выполнения конкретных действий, выполнение которых отвлекает хозяев от их обыденной жизни, и уходит, получив конкретное возмещение за проделанный труд. Конечно, можно переложить на него и дополнительные обязанности, но это потребует от хозяев вложения дополнительных средств.
Если стоит необходимость проектирования и реализации системы или ее модуля с использованием существующих компонентов, на уже реализованные связи между этими компонентами можно характеризовать феноменом "Спагетти-кода", стоит задуматься о применении шаблона проектирования "Посредник".
"Спагетти-код"– низкоструктурированная, запутанная и трудная для понимания программа. "Спагетти-код" назван так, потому что ход выполнения программы похож на миску спагетти–извилистый и запутанный.
Шаблон "Посредник" применяется в том случае, когда необходимо обеспечить взаимодействие множества объектов, сформировав при этом слабую связанность и избавив объекты от необходимости явно ссылаться друг на друга.
"Посредник" используется в системах, где взаимодействие между компонентами может быть весьма сложным, но хорошо определенным. Особенно актуальным является внедрение этого паттерна, если есть предпосылки к тому, что связи между модулями будут постоянно расти и усложняться. Шаблон "Посредник" можно сравнить с уже рассмотренным ранее архитектурным шаблоном "Диспетчер". Они выполняют схожие функции, но обладают разными обязанностями.
Для реализации шаблона "Посредник" потребуется:
Шаблон "Посредник" определяет объект, управляющий набором взаимодействующих объектов. Слабая связанность достигается благодаря тому, что вместо непосредственного взаимодействия друг с другом коллеги общаются через объект-посредник.
Для того чтобы внедрение шаблона "Посредник" в программу было выполнено наиболее эффективным образом, необходимо предварительно:
Применение шаблона "Посредник" позволяет:
Недостатки же его использования следующие:
"Посредник" выполняет функцию организации взаимодействия между существующими элементами, которые выполняют свои обязанности, и новыми компонентами, в которых использование существующих элементов приносит дополнительную ценность программному продукту, выраженную, как правило, в экономии ресурсов на его реализацию.
В ситуациях, когда требуется варьировать поведение объекта в зависимости от его внутреннего состояния, используют шаблон проектирования cодноименным названием–"Состояние".
Состояние каждого объекта определяется его поведением и изменяется во время выполнения программы. Текущее состояние объекта запускает ряд функций, выполнение которых переводит объект в другие состояния. Но объекты, обладающие большим числом состояний, как правило, содержат сложные механизмы диверсификации и структуру кода. Преодоление этого недостатка решается за счет рассматриваемого паттерна.
Структура этого паттерна определяется следующим образом:
Реализацию паттерна "Состояние" можно организовать следующим способом:
Использование шаблона "Состояние" локализует зависящее от состояния поведение и делит его на части, соответствующие состояниям, переходы между состояниями становятся явными, а процесс работы с объектом – более прозрачным и понятным.
Реализация статусной модели похожа на ожидание возможности перехода у светофора. Когда загорается красный свет, все участники движения понимают, что настал момент, когда автомобилисты должны остановиться и пропустить пешеходов. Загоревшийся зеленый свет оповещает о том, что теперь пешеходы должны переходить дорогу.
(рис 6.2.8) Шаблон "Состояние"
В ситуациях, когда определенный класс содержит ряд схожих алгоритмов (способов сделать то или иное действие), как правило, эти алгоритмы приводят к одному и тому же результату, но могут отличаться по другим параметрам (время выполнения, потребление системных ресурсов и др.).В подобных ситуациях целесообразно использовать шаблон "Стратегия".
В основной идее данного шаблона лежит необходимость выделения семейства схожих алгоритмов и инкапсуляции каждого из них в собственный класс. После этого алгоритмы можно заменять прямо во время исполнения программы.
Для реализации данного шаблона потребуется:
Применение шаблона "Стратегия" позволяет сделать специализированные модули программного обеспечения более понятными, читаемыми и однозначными.
К основным преимуществам использования этого шаблона следует отнести следующие:
Если провести "жизненную" аналогию по применению этого шаблона, то уместным будет следующее сравнение:
(рис 6.2.9) Шаблон "Стратегия"
Когда необходимо зафиксировать поведение объекта для его последующей реализации, применяется шаблон "Хранитель".
Этот шаблон применяется, если требуется зафиксировать и вынести (не нарушая структуры программы) за пределы объекта его внутреннее состояние так, чтобы впоследствии можно было восстановить в нем объект.
Таким образом, не нарушая принципа инкапсуляции, шаблон "Хранитель" получает и сохраняет за пределами объекта его внутреннее состояние так, чтобы позже можно было восстановить объект в первоначальном состоянии.
Особенно актуально применение этого паттерна в ситуации, когда нужно восстановить объект обратно в прежнее состояние.
Для реализации данного шаблона обязательно должны быть определены 3 различных "участника":
Алгоритм выполнения шаблона "Хранитель" определяется следующим образом:
Основные недостатки и издержки использования этого шаблона проектирования связаны с объемом объекта "Хозяин". Если он слишком велик, то "Хранитель" должен копировать большой объем информации. Если структура программного продукта подразумевает частое использование шаблона "Хранитель", то требуются значительные системные ресурсы для поддержки производительности программного обеспечения.
Шаблон проектирования "Хранитель" фиксирует и сохраняет за пределами объекта "Хранителя" его внутреннее состояние так, чтобы позже этот объект можно было бы восстановить в таком же состоянии.
Этот шаблон используется в функциональности тех приложений, когда есть возможность отменить последнее действие и вернуть систему в предыдущее состояние.
Хорошей жизненной аналогией данного паттерна является коробка с паззлом, на передней части которой изображена картина в целом. Именно напоминание картины в целом –это "Хранитель" конечного состояния объекта.
В случаях, когда требуется эффективно, компактно, надежно реализовать обработку потока информации с потенциально большим количеством обработчиков, используется шаблон проектирования "Цепочка обязанностей".
В современных системах количество обработчиков во многом определяет оперативность выполнения системой ее функций, поэтому их количество, как правило, достаточно велико.
С одной стороны, все прозрачно и понятно–есть множество типов сообщений, есть множество обработчиков этих сообщений. Задача системы состоит в том, чтобы обрабатывать каждое сообщение в потоке ассоциированным с его конкретным типом обработчика.
Паттерн "Цепочка обязанностей" позволяет реализовать эффективный механизм увязывания типов сообщений и обработчиков.
Если в системе небольшое число обработчиков, то достаточно реализовать данный механизм на базе цикличной конструкции (if, case, whileи пр.). Однако по мере роста и развития систем появляются дополнительные значимые нюансы:
Основная идея этого шаблона заключается в организации конвейера из обработчиков, в котором каждый может либо обработать поступившее сообщение, либо делегировать обработку следующему в конвейере обработчику. Возможен еще вариант обработки и последующей передачи:
Шаблон "Цепочка обязанностей" позволяет:
Этот шаблон проектирования достаточно требователен к системным ресурсам. В частности, необходимо убедиться, что программа корректно "отлавливает" случаи необработанных запросов.
"Жизненным" примером этого шаблона является компьютерная сеть–большое количество обработчиков, узлов сети (компьютеров, серверов, маршрутизаторов) и еще большее количество типов сетевых запросов:
(рис 6.2.11) Шаблон "Цепочка обязанностей"
Когда имеются два разных, но в тоже время очень похожих компонента и требуется внести изменения в оба компонента, избежав при этом вредоносного дублирования кода, применяется паттерн "Шаблонный метод".
"Шаблонный метод" определяет основной алгоритм и позволяет подклассам изменить некоторые шаги этого алгоритма без изменения его общей структуры.
Для применения этого шаблона необходимо исследовать общий алгоритм и определить, какие его шаги и стадии являются стандартными, то есть общими, а какие должны определяться подклассами в зависимости от условий конкретной задачи. Создается абстрактный базовый класс, в котором реализован принцип общности и определения стандартных шагов. Если для некоторых шагов требуются различные реализации, то определяются "замещающие" методы:
"Шаблонный метод" широко применяется в каркасах приложений разработки программного обеспечения. Каждый каркас реализует неизменные части архитектуры в предметной области, а также определяет те части, которые могут или должны настраиваться для конкретного случая. Таким образом, каркас приложения становится "солнцем", а настройки являются "планетами".
Строители зданий используют паттерн "Шаблонный метод" при проектировании новых домов. Используются типовые, хорошо себя зарекомендовавшие планы, в которых модифицируются отдельные части, не влияющие на основные архитектурные компоненты.
Шаблон "Высокое зацепление" решает задачу управления сложностью программного обеспечения за счет регулирования степени зацепления системных классов между собой.
Понятия зацепления и связанности достаточно часто встречаются в профильной литературе, описывающей принципы современных программных продуктов. Принято считать, что каждая информационная система, спроектированная в соответствии с отраслевыми стандартами, должна удовлетворять принципам низкой связности и высокого зацепления ее внутренних модулей.
Стоит пояснить, что разница между связностью и зацеплением достаточно большая, но не совсем очевидная. Вкратце разницу понятий можно охарактеризовать следующим образом:
Элемент обладает высокой степенью зацепления, если его обязанности тесно связаны между собой, и он не выполняет огромных объемов работы. Класс с низкой степенью зацепления выполняет много разнородных функций или несвязанных между собой обязанностей.
Реализация шаблона "Высокое зацепление" позволяет легко модифицировать и сопровождать программное обеспечение, повышает возможность его повторного использования.
Мера связности модулей определяется количеством информации, которой располагает один модуль о природе другого. В свою очередь, мера зацепления модуля определяется степенью сфокусированности его обязанностей.
Принципы реализации высокого зацепления утверждают, что класс должен стараться выполнять как можно меньше неспецифичных для него задач и иметь вполне определенную область применения. Считается что связывание и зацепление –это "инь" и "янь" проектирования ПО. Некорректное связывание порождает неправильное зацепление, и наоборот.
В условиях, когда система должна отвечать за обработку большого количества входных системных событий, целесообразно использовать шаблон "Контроллер".
Суть реализации шаблона "Контроллер" состоит в определении обязанности по обработке системных сообщений, которые должны быть делегированы специальному классу или классам.
"Контроллер"– это объект, который отвечает за обработку системных событий и не относится к интерфейсу пользователя. "Контроллер" определяет методы выполнения системных операций.
Паттерн "Контроллер" призван решить наболевшую проблему разделения интерфейса и логики в интерактивном приложении.
Если вспомнить изученный ранее архитектурный шаблон MVC, то шаблон проектирования "Контроллер" отвечает за организацию компоненты, скрывающейся под символом "С":
Системный компонент, реализуемый по шаблону "Контроллер", должен удовлетворять следующим условиям:
Для различных экземпляров процесса обработки входных сообщений ("прецедентов") логично использовать разные контроллеры ("контроллеры прецедентов").Контроллеры не должны быть перегружены, иначе это приведет к ошибкам при отработке логики приложения.
Шаблон "Контроллер" является не объектом автоматизации предметной области, а искусственной конструкцией, которая выполняется в соответствии с четко определенными правилами.
"Контроллер" выполняет роль универсального и добросовестного постового, который следует общим правилам и не допускает возникновения заторов и пробок. Его задача –следить за выполнением установленного процесса и корректировать ход его исполнения в случаях, когда кто-то из участников дорожного движения вышел за рамки установленных правил.
Принцип полиморфизма является основополагающим для современной парадигмы объектно-ориентированного программирования. В контексте применения шаблонов проектирования паттерн "Полиморфизм" призван решать задачу обработки вариантов поведения системы на основе типа обрабатываемого сообщения или данных. Лучше всего эта задача решается с использованием полиморфных операций. Кроме того, при помощи шаблона "Полиморфизм" легко создавать подключаемые к системе компоненты. В итоге использование принципов полиморфизма позволяет получить следующие преимущества:
Но не следует злоупотреблять добавлением интерфейсов с применением принципа полиморфизма, если поведение внешней системы изучено не до конца. Это может привести к возникновению большого числа отложенных ошибок.
Что необходимо сделать для перераспределения обязанностей между объектами, чтобы обеспечить отсутствие прямого связывания, которое влияет на гибкость системы в целом?
Наиболее очевидным вариантом является делегирование обязанности обеспечения связи между службами или компонентами специализированному промежуточному объекту. Рассматриваемый шаблон "Перенаправление" разработан для решения задачи прямой связности.
Паттерн реализует низкую связность между классами, путем назначения обязанностей по их взаимодействию дополнительному объекту – посреднику.
В этой главе мы изучили поведенческие шаблоны проектирования. Эта группа шаблонов является логичным продолжением рассмотренных нами ранее структурных шаблонов, но их специфическое назначение связано с регламентацией поведения системных объектов, т.е. особенностей их функционирования.
Поведенческие шаблоны, с точки зрения вклада в архитектурное проектирование, являются связующим звеном между структурными, порождающими и архитектурными, интеграционными шаблонами.
Оптимальное использование поведенческих шаблонов позволит нивелировать недостатки неудачно спроектированного программного обеспечения, снизить отдельные, наиболее отрицательные или повысить удачные характеристики программного продукта.
Именно высокий уровень владения деталями реализации поведенческих паттернов поможет разработчику информационной системы оперативно устранить самые значимые недостатки отдельных компонентов информационной системы.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.