Принципы работы с шаблонами проектирования
В распоряжение проектировщика предоставлен каталог из более чем 20 шаблонов, и поэтому трудно решить, какой шаблон лучше всего подходит для конкретной задачи.
Можно привести следующие подходы к выбору подходящего шаблона: следует обдумать, как шаблоны решают проблему проектирования; проанализировать назначение шаблонов; изучить взаимосвязи шаблонов; проанализировать шаблоны со сходными целями; разобраться в причинах, вызывающих перепроектирование; посмотреть, что в дизайне должно изменяться.
Работа с шаблонами состоит из следующих этапов.
1. Прочитайте описание шаблона, чтобы получить о нем общеепредставление.
2. Убедитесь, что понимаете, что представляют собой упоминаемые в шаблоне классы и объекты, и то, как они взаимодействуютдруг с другом.
3. Выберите для участников шаблона подходящие имена. Именаучастников шаблона обычно слишком абстрактны, чтобы употреблятьих непосредственно в коде. Тем не менее, бывает полезно присвоитьучастнику такое же имя, как в программе. Например, если используется шаблон «стратегия в алгоритме размещения текста», то классымогли бы называтьсяSimpleLayoutStrategyилиTeXLayoutStrategy.
4. Определите классы, объявите их интерфейсы, установите отношения наследования и определите переменные экземпляра, которыми будут представлены данные объекты и ссылки на другие объекты. Выявите имеющиеся в вашем приложении классы, на которыешаблон оказывает влияние, и соответствующим образом модифицируйте их.
5. Определите имена операций, встречающихся в шаблоне. Здесь, как и в предыдущем случае, имена обычно зависят от приложения. Руководствуйтесь теми функциями и взаимодействиями, которыеассоциированы с каждой операцией. Кроме того, будьте последовательны при выборе имен. Например, для обозначения фабричногометода можно было бы всюду использовать префикс «Create».
6. Реализуйте операции, которые выполняют обязанности и отвечают за отношения, определенные в шаблоне.
Основные типы шаблонов
Приведем краткий обзор шаблоновпроектирования (таблица 16.1).
Таблица 16.1. Шаблоны проектирования и их краткое описание
Порождающие шаблоны | Абстрактная фабрика | Семейства порождаемых объектов |
Одиночка | Единственный экземпляр класса | |
Прототип | Класс, из которого инстанцируется объект | |
Строитель | Способ создания составного объекта | |
Фабричный метод | Инстанцируемый подклассобъекта | |
Структурные шаблоны | Адаптер | Интерфейс к объекту |
Декоратор | Обязанности объекта без порождения подкласса | |
Заместитель | Способ доступа к объекту, егоместоположение | |
Компоновщик | Структура и состав объекта | |
Мост | Реализация объекта | |
Приспособленец | Накладные расходы при хранении объектов | |
Фасад | Интерфейс к подсистеме | |
Шаблоны поведения | Интерпретатор | Грамматика и интерпретацияязыка |
Итератор | Способ обхода элементов агрегата | |
Команда | Время и способ выполнения запроса | |
Наблюдатель | Множество объектов, зависящихот другого объекта Способ, которым зависимые объекты поддерживают себя в актуальном состоянии | |
Посетитель | Операции, которые можно применить к объекту или объектам не меняя класса | |
Посредник | Объекты, взаимодействующиемежду собой, и способ их коопераций | |
Состояние | Состояние объекта | |
Стратегия | Алгоритм | |
Хранитель | Закрытая информация, хранящаяся вне объекта, и время еесохранения | |
Цепочка обязанностей | Объект, выполняющий запрос | |
Шаблонный метод | Шаги алгоритма |
Порождающие шаблоны абстрагируют процесс создания экземпляров классов и помогают сделать систему независимой от способасоздания, композиции и представления объектов. Шаблоны, порождающие классы, используют наследование, чтобы различать создаваемые экземпляры, а шаблоны, порождающие объекты, поручаютсоздание другим объектам. Данный тип шаблонов важен, когда система больше зависит от композиции объектов, чем от наследованияклассов. Порождающий шаблон обеспечивает большую гибкость прирешении вопроса о том, что создается, кто это создает, как и когда. Можно собрать систему из «готовых» объектов с самой различнойструктурой и функциональностью статически (на этапе компиляции) или динамически (во время выполнения).
В качестве примера можно привести известный шаблон «Фабрика классов», который позволяет порождать объекты одинаковойструктуры, но с различными свойствами, используя полиморфныеклассы (например, порождение одного и того же лабиринта, с различными свойствами его элементов, в зависимости от класса, который их создает.
Структурные шаблоны служат для рассмотрения вопроса о том, как из классов и объектов образуются более крупные структуры. Структурные шаблоны уровня класса используют наследование длясоставления композиций из интерфейсов и реализаций. В качествепростого примера можно привести использование множественногонаследования для объединения нескольких классов в один. В результате получается класс, обладающий свойствами всех своих родителей. Вместо композиции интерфейсов или реализаций структурные шаблоны уровня объекта компонуют объекты для получения новойфункциональности. Дополнительная гибкость в этом случае связанас возможностью изменять композицию объектов во время выполнения, что недопустимо при статической композиции классов.
Примером структурного шаблона уровня объектов является «Компоновщик». Он описывает построение иерархии классов для двухвидов объектов: примитивных и составных. Последние позволяютсоздавать произвольно сложные структуры из примитивных и другихсоставных объектов. В шаблоне «Заместитель» объект берет на себяфункции другого объекта. У «заместителя» есть много применений. Он может действовать как локальный представитель объекта, находящегося в удаленном адресном пространстве, или представлятьбольшой объект, загружаемый по требованию, или ограничиватьдоступ к критически важному объекту. «Заместитель» вводит дополнительный косвенный уровень доступа к отдельным свойствам объекта, поэтому он может ограничивать, расширять или изменять этисвойства. Шаблон «Приспособленец» определяет структуру для совместного использования объектов. Он акцентирует внимание наэффективности использования памяти. В приложениях, где участвует много объектов, должны снижаться накладные расходы на иххранение (примером может служить программа, которая реализуеттекстовый редактор, поддерживающий произвольное форматирование любых участков текста). Шаблон «Фасад» представляет наборобъектов и выполняет свои функции, перенаправляя сообщенияобъектам, которые он представляет. Шаблон «Мост» отделяет абстракцию объекта от его реализации, так что их можно изменятьнезависимо.
Шаблоны поведения связаны с алгоритмами и распределениемобязанностей между объектами, предназначены больше для проектирования типичных способов взаимодействия между объектами иклассами. Шаблоны поведения характеризуют сложный поток управления, который трудно проследить во время выполнения программы. Внимание акцентировано не на потоке управления как таковом, ана связях между объектами. В шаблонах поведения уровня классаиспользуется наследование, чтобы распределить поведение междуразными классами, например шаблон, описывающий абстрактноеопределение алгоритма, где алгоритм определяется пошагово. Накаждом шаге вызывается либо примитивная, либо абстрактная операция. Алгоритм усложняется, детализируется за счет подклассов, гдеопределены абстрактные операции.
В качестве примера можно взять шаблон «Интерпретатор», который представляет грамматику произвольного языка в виде иерархииклассов и реализует интерпретатор как последовательность операцийнад экземплярами этих классов. В шаблонах поведения уровня объектов используется не наследование, а композиция. Некоторые изних описывают, как с помощью кооперации множество равноправных объектов справляется с задачей, которая ни одному из них непод силу. Например, при максимальной степени связности каждомуобъекту пришлось бы иметь информацию обо всех остальных. Этупроблему решает шаблон «Посредник», находящийся междуобъектами-коллегами, обеспечивая косвенность ссылок, необходимую для разрыва лишних связей.
Пример 16.1. Рассмотрим пример реализации шаблона «Одиночка».
Название и классификация шаблона: Одиночка (Singleton) – шаблон, порождающий объекты.
Назначение. Гарантирует, что у класса есть только один экземпляр, ипредоставляет к нему глобальную точку доступа.
Мотивация. Для некоторых классов важно, чтобы существовал толькоодин экземпляр, например: в системе может быть много принтеров, но возможен лишь один диспетчер печати; должны быть только одна файловаясистема и единственный оконный менеджер; в цифровом фильтре можетнаходиться только один аналого-цифровой преобразователь; в программеглобальные настройки должны храниться в едином хранилище.
Как гарантировать, что у класса есть единственный экземпляр и чтобыэтот экземпляр был легко доступен? Глобальная переменная дает доступ кобъекту, но не запрещает создавать несколько экземпляров класса. Болееудачное решение – сам класс контролирует то, что у него есть только одинэкземпляр, и может запретить создание дополнительных экземпляров, перехватывая запросы на создание новых объектов, он же способен предоставитьдоступ к своему экземпляру. Это и есть назначение шаблона «Одиночка».
Применимость. Используйте паттерн «Одиночка», когда должен бытьровно один экземпляр некоторого класса, доступный всем клиентам, илиединственный экземпляр должен расширяться путем порождения подклассови клиентам нужно иметь возможность работать с расширенным экземпляромбез модификации своего кода. Структура паттерна «Синглетон» представлена на рис. 16.1.
Рисунок 16.1. Структура шаблона «Одиночка»/
Участники. «Singleton» – одиночка: определяет операцию Instance, которая позволяет клиентам получать доступ к единственному экземпляру(Instance– это статический метод класса); может нести ответственность засоздание собственного уникального экземпляра.
Отношения. Клиенты получают доступ к экземпляру класса Singletonтолько через его операцию Instance.
Результаты. У шаблона «Одиночка» есть следующие достоинства. Контролируемый доступ к единственному экземпляру. Поскольку класс Singletonинкапсулирует свой единственный экземпляр, он полностью контролируетто, как и когда клиенты получают доступ к нему.
Также следует отметить уменьшение числа имен. Шаблон позволяет избежать засорения пространства имен глобальными переменными, в которыххранятся уникальные экземпляры.
Кроме того, шаблон допускает уточнение операций и представления. От класса Singleton можно порождать подклассы, а приложение легко настроить экземпляром расширенного класса. Можно конкретизироватьприложение экземпляром того класса, который необходим во время выполнения.
Шаблон допускает переменное число экземпляров, т. е. позволяет легкоизменить решение и разрешить появление более одного экземпляра классаSingleton. Можно применять один и тот же подход для управления числомэкземпляров, используемых в приложении. Изменить нужно будет лишьоперацию, дающую доступ к экземпляру класса Singleton. Реализация шаблона представлена листингом
Листинг 16.1. Пример реализации шаблона «Одиночка»
classSingleton
{
// Статическийэкземпляркласса
private static Singleton _Instance = null;
// Конструктор
privateSingleton()
{
}
// Получение экземпляра класса
public static Singleton Instance();
{
if (_Instance == null)
_Instance = new Singleton ();
return _Instance;
}
}
При использовании шаблона «Синглетон» предусмотрено следующее. Гарантирована единственность экземпляра. Шаблон «Одиночка» устроентак, что больше одного экземпляра создать не удастся. Для этого прячутоперацию, создающую экземпляры, за статической функцией-членом илиметодом класса, которые гарантируют создание не более одного экземпляра. Данная операция имеет доступ к статическому полю класса, гдехранится уникальный экземпляр, и гарантирует инициализацию переменной этим экземпляром перед возвратом ее клиенту. При таком подходе «Одиночка» будет создан и инициализирован перед первым использованием.
Клиенты осуществляют доступ к «Одиночке» исключительно через статический метод Instance. Переменная _Instance инициализируется пустымзначением Null, а статический метод Instanceвозвращает ее значение, инициализируя ее уникальным экземпляром, если в текущий момент оно равноNull. Метод Instance использует отложенную инициализацию: возвращаемоеей значение не создается и не хранится вплоть до момента первого обращения.
Необходимо отметить, что конструктор защищенный (private). Клиент,который попытается создать экземпляр класса Singleton непосредственнополучит ошибку на этапе компиляции. Это дает гарантию, что будет создантолько один экземпляр.
Поскольку переменная _Instance– указатель на объект класса Singleton, то функция-член Instance может присвоить этой переменной указатель налюбой подкласс данного класса.
Программные средства
При конструировании ПО обычно используют так называемыесреды разработки, т. е. системы программных средств для разработки программного обеспечения.
Существуют и широко используются следующие интегрированныесреды разработки, предназначенные для нескольких языков программирования.
Eclipse–cвободная интегрированная среда разработки модульныхкроссплатформенных приложений, поддерживает разработку наязыках Java, C/C++, Fortran, Perl, PHP, JAVASCRIPT, Python, Ruby;
NetBeans– интегрированная среда разработки приложений, поддерживает разработку на языках Java, JAVAFX, Python, PHP, JAVASCRIPT, C++, Ada.
Embarcadero RAD Studio– среда быстрой разработки приложенийдляMicrosoftWindowsфирмыEmbarcaderoTechnologies. ТекущаяверсияEmbarcaderoRADStudioXE3 объединяетDelphiXE3 иC++ BuilderXE3, DelphiPrismXE3 иHTML5 Builderвединуюинтегрированную среду разработки;
QtCreator– свободная среда разработки для языков С, С++ иQML.
MicrosoftVisualStudio– интегрированная среда разработкикомпании Microsoft, позволяет создавать приложения на языках C/C++, VisualBasic, C#, J#, F# и проекты для баз данных Microsoft SQLServer, включает в себя множество дополнительных инструментов, атакже функционал для командной разработки и создания тестов.
Не менее популярны и среды разработки, предназначенные дляодного определенного языка программирования.
VisualBasic– среда разработки на одноименном языке.
BorlandDelphi– среда разработки на языке ObjectPascal.
Borland C++ Builder– среда разработки на C++.
Dev-C++– среда разработки на C++.