Теоретические аспекты паттерного программирования

УДК: 004 ББК: 32.973.26-018

Крайнова Е.А.

ТЕОРЕТИЧЕСКИЕ АСПЕКТЫ ПАТТЕРНОГО ПРОГРАММИРОВАНИЯ

Kraynova E.A.

THEORETICAL ASPECTS OF DESIGN PATTERNS

Ключевые слова: программирование, парадигма, объектно-ориентированное программирование, технология программирования, паттерны проектирования, порождающие паттерны, структурные паттерны, паттерны поведения.

Keywords: programming, paradigm, object-oriented programming, technology of programming, design patterns, creational patterns, structural patterns, behavioral patterns.

Аннотация: представлены тенденции развития технологий программирования, современные парадигмы программирования. Дано понятие объектно-ориентированного программирования, паттернов проектирования на его основе. Структурированы наиболее часто применяемые паттерны проектирования систем и дана их характеристика.

Abstract: shows the trends of programming development, advanced programming paradigm. Given the concept of technologies object-oriented programming, design patterns based on it. Structured the most frequently used design patterns systems and given their characteristics.

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

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

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

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

В общенаучном смысле парадигма (от греч. ларабегуца, «пример, модель, обра-

зец») - совокупность фундаментальных научных установок, представлений и терминов, принимаемая и разделяемая научным сообществом и объединяющая большинство его членов. Под парадигмой программирования понимают систему идей и понятий, определяющих стиль написания компьютерных программ. Это способ концептуализации, определяющий организацию вычислений и структурирование работы, выполняемой компьютером [12].

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

Директивное программирование довольно легко для понимания, так как в программе пошагово описываются действия, ведущие от исходных данных к конечному результату. В таких программах от входных данных полностью зависит последовательность выполнения команд. Именно в структурном программировании возникла концепция локализации части кода в так называемые подпрограммы (функции, процедуры), с последующим их вызовом из разных мест основной программы. В качестве представителей языков, основанных на директивной парадигме, можно назвать Fortran, Pascal, C.

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

вызвавшую ее функцию, и после этого продолжается вычисление до тех пор, пока не будет достигнут конечный результат. Логическое программирование представляет программы с помощью формул математической логики, а результат достигается выводом логических следствий из них. Представители функциональных языков: List, Haskell, представитель логических языков: Prolog [10].

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

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

Термин «паттерн» впервые в 1970-е годы применил архитектор Кристофер Александр, описав шаблоны, возникающие при проектировании зданий и городов. По его словам «любой паттерн описывает задачу, которая снова и снова возникает в нашей работе, а также принцип ее решения, причем таким образом, что это решение можно потом использовать миллион раз, ничего не изобретая заново» [1]. Несмотря на то, что автор имел ввиду архитектурные решения, его слова верны и в отношении объектно-ориентированного программирования.

В 1987 году идеи Александра развили американские программисты Уорд Каннин-гем и Кент Бэк, разработав шаблоны для классов MVC (Model/View/Controller) для разработки графических оболочек на языке Smalltalk

Причиной роста популярности применения паттернов проектирования стал выход книги Эриха Гамма «Design Patterns -Elements of Reusable Object-Oriented Software», основанной на результатах докторской диссертации об общей переносимости паттерной методики на разработку программ. В настоящее время команда авторов книги занимает лидирующую позицию в области паттерного проектирования.

Паттерн проектирования в общем случае состоит из следующих элементов:

- Имя. Ссылка на имя позволяет описать проблему, способы ее решения и их последствия. Использование имен повышает уровень абстракции проектирования.

- Задача. Описывает ситуации, в которых применяется паттерн. Формулируется задача и ее контекст, описывается конкретная проблема и условия применения данного паттерна.

- Решение. Содержит элементы дизайна, их описание, взаимодействие, функции, при этом не рассматриваются конкретные дизайн или реализация, так как паттерн - это

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

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

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

Описание и документирование основных паттернов объектно-ориентированного проектирования дано в книге [13], согласно которой паттерны классифицируются (таблица 1) по двум критериям:

1) цель - назначение паттерна;

2) уровень - применение паттерна к определенному иерархическому уровню: классу или объекту.

Уровень Назначение

Порождающие паттерны Структурные паттерны Паттерны поведения

Класс Фабричный метод Интерпретатор Шаблонный метод

Объект Абстрактная фабрика Одиночка Прототип Строитель Адаптер (объекта) Декоратор Заместитель Компоновщик Мост Приспособленец Фасад Итератор Команда Наблюдатель Посетитель Посредник Состояние Стратегия Хранитель Цепочка обязанностей

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

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

- название и классификация;

- назначение;

- альтернативное имя (другие известные названия паттерна);

- применимость;

- результаты.

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

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

Описание порождающих паттернов, перечисленных в таблице 1, будем вести согласно вышеуказанному плану и для удобства сведем в таблицу 2.

Таблица 2 - Порождающие паттерны

Паттерн Абстрактная фабрика

Название и классификация Абстрактная фабрика (Abstract Factory) - паттерн, порождающий объекты

Назначение Предоставляет интерфейс для взаимозависимых или взаимосвязанных объектов без спецификации их конкретных классов

Альтернативное имя Kit

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

Результаты Достоинства: - изоляция конкретных классов; - упрощение замены семейств продуктов; - гарантия сочетаемости продуктов. Недостаток: - затруднения в проектировании новых видов продуктов.

Паттерн Строитель

Название и классификация Builder (Строитель) - паттерн, порождающий объекты

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

Альтернативное имя -

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

Результаты Достоинства: - возможность изменения внутреннего представления продукта; - изоляция кода, реализующего конструирование и представление; - предоставление более тонкого контроля над процессом проектирования.

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

Название и классификация Factory Method (Фабричный метод) -паттерн, порождающий классы

Назначение Определяет интерфейс для создания объекта, оставляя подклассам возможность принятия решения о том, какой класс инстанцировать

Альтернативное имя Virtual Constructor

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

Результаты Достоинства: - освобождение проектировщика от необходимости встраивания в код зависящих от приложения классов; - предоставление подклассам операции-зацепки (hooks); - соединение параллельных операций. Недостаток: - проектирование подкласса для создания лишь для одного объекта.

Паттерн Прототип

Название и классификация Prototype (Прототип) - паттерн, порождающий объекты

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

Альтернативное имя -

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

Результаты Достоинства: - возможность удаления и добавления продуктов непосредственно во время выполнения; - построение новых объектов посредством изменения структуры; - уменьшение числа подклассов; - возможность динамического конфигурирования приложения классами. Недостаток: - сложности в реализации операции клонирования.

Паттерн Одиночка

Название и классификация Singleton (Одиночка) -паттерн, порождающий объекты

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

Альтернативное имя -

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

Результаты Достоинства: - предоставление контролируемого доступа к единственному экземпляру; - уменьшение числа имен; - допущение уточнения операций и представления; - допущение изменения числа экземпляров; - большая гибкость, чем у операций класса.

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

обладает свойствами всех своих родителей. Структурные паттерны уровня объекта позволяют компоновать объекты для получения новой функциональности. Рассмотрим наиболее часто применяемые и распространенные структурные паттерны: адаптер, компоновщик, декоратор (таблица 3).

Таблица 3 - Структурные паттерны

Паттерн Адаптер

Название и классификация Adapter (Адаптер) -паттерн, структурирующий классы и объекты

Назначение Преобразует интерфейс одного класса в интерфейс другого по заказу клиента, обеспечивает совместную работу классов с несовместимыми интерфейсами

Альтернативное имя Wrapper

Применимость Используется в случаях, если: - требуется использовать существующий класс с неудовлетворяющим потребителя интерфейсом; - необходимо создать повторно используемый класс, который будет взаимодействовать с классами или с классами с несовместимыми интерфейсами

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

Паттерн Компоновщик

Название и классификация Composite (Компоновщик) - паттерн, структурирующий объекты

Назначение Компонует объекты в древовидные структуры для представления иерархий часть-целое, что обеспечивает единообразие в трактовке индивидуальных и составных объектов

Альтернативное имя -

Применимость Используется в случаях, если: - требуется представление иерархии часть-целое; - для клиентов важно единообразие трактовки составных и индивидуальных объектов.

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

Паттерн Декоратор

Название и классификация Decorator (Декоратор) -паттерн, структурирующий объекты

Назначение Динамически добавляет объекту новые функциональные обязанности

Альтернативное имя Wrapper

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

Результаты Достоинства: - большая гибкость, чем у статического наследования; - позволяет избежать перегруженных функциями классов на верхних уровнях иерархии; Недостатки: - декоратор и его компонент идентичны; - появление множества мелких объектов.

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

Таблица 4 - Паттерны поведения

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

Паттерн Наблюдатель

Название и классификация Observer (Наблюдатель) -паттерн поведения объектов

Назначение Определяет зависимость «один-ко-многим» между объектами

Альтернативное имя Dependents

Применимость Используется в случаях, если: - у абстракции есть два аспекта, один из которых подчиняется другому; - заранее неизвестно, сколько подчиненных объектов требуется изменить; - необходимо автоматическое обновление всех связанных объектов.

Результаты Достоинства: - абстрактная связанность субъекта и наблюдателя; - поддержка широковещательных коммуникаций. Недостаток: - неожиданные обновления.

Паттерн Стратегия

Название и классификация Strategy (Стратегия) -паттерн поведения объектов

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

Альтернативное имя Policy

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

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

Паттерн Шаблонный метод

Название и классификация Template Method (Шаблонный метод) -паттерн поведения классов

Назначение Определяет основу алгоритма и позволяет подклассам переопределить некоторые шаги алгоритма, не изменяя его структуру в целом

Альтернативное имя -

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

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

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

вания определяет символы для моделирова- В лучших проектах используется много

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

Важным дополнением к методам объ- дра: «Mожно строить здания, нанизывая пат-ектно-ориентированного программирования терны в достаточно произвольном порядке. являются паттерны. С их помощью можно Такое здание будет просто собранием паттер-увидеть способы применения таких базовых нов. В нем нет плотности. Нет основательно-понятий, как объекты, наследование и поли- сти. Но можно объединять паттерны и так, что морфизм, паттерны позволяют не просто за- в одном и том же физическом объеме они бу-фиксировать результаты решений, но и полу- дут перекрывать друг друга. Тогда здание почить ответы на многочисленные вопросы, воз- лучается очень плотным, в небольшом проникающие в ходе проектирования. Особенно странстве сосредотачивается много функций. полезны они на этапе преобразования анали- За счет такой плотности здание приобретает тической модели в модель реализации. В гиб- основательность» [1]

БИБЛИОГРАФИЧЕСКИЙ СПИСОК

1. Cristofer, Alexandr, Sara, Ishikawa, Murray, Silverstein, Max, Jacobson, Ingrid, Fiksdahl-King and Shlomo Angel. A Pattern Language/ Oxford University Press, New York, 1977.

2. Erich, Gamma. Object-Oriented Software Development based on ET++: Design Patterns, Class Library, Tools (in German). PhD thesis, University of Zurich Institut fur Informatik, 1991.

3. Erich, Gamma. Object-Oriented Software Development based on ET++: Design Patterns, Class Library, Tools (in German). - Springer-Verlag, Berlin, 1991.

4. G., Hohpe, B., Woolf. Enterprise Integration Patterns : Designing, Building, and Deploying Messaging Solutions. - Addison-Wesley, 2GG4.

5. Алан, Шаллоуей, Джеймс, Р. Тротт Шаблоны проектирования. Новый подход к объектно-ориентированному анализу и проектированию. - M.: Вильямс, 2GG2. - 288 с.

6. Дуглас, Шмидт, Стивен, Хьюстон. Программирование сетевых приложений на С++. Том 1. Профессиональный подход к проблеме сложности: ACE и паттерны. - Бином-Пресс, 2GG3. - 304 с.

7. Кржиштоф, Цвалина, Брэд, Абрамс. Инфраструктура программных проектов. Соглашения, идиомы и шаблоны для многократно используемых библиотек. NET (+ CD-ROM). - Вильямс, 2011. - 416 с.

В. Фаулер, M. Архитектура корпоративных программных приложений. - M., Вильямс, 2004.

9. Дубинина, О. Обзор паттернов проектирования. URL http://citforum.ru/SE/ project/pattern/

1G. Программирование. URL http://www.inf1.info/book/export/html/216

11. Mартин, Р.С., Mартин, M. Принципы, паттерны и методики гибкой разработки на языке C#. - Символ-Плюс, 2011. - 768 с.

12. Роганов, Е.А. Основы информатики и программирования. - M.: ЫГИУ, 2001.

13. Гамма, Э., Хелм, Р., Джонсон, Р., Влиссидес, Дж. Приемы объектно-ориентированного проектирования. Паттерны проектирования. - СПб.: Питер, 2G1G. - 366 с.

14. Фримен, Э., Фримен, Э., Сьерра, К., Бейтс, Б. Паттерны проектирования. - СПб.: Питер, 2G11. - 656 с.

15. Хант, Э., Томас, Д. Программист-прагматик. Путь от подмастерья к мастеру. - M.: Лори, 2009. - 270 с.

Вестник Волжского университета имени В.Н. Татищева №2