Моделирование и проектирование программного обеспечения Лекция xx. Проектирование связей между классами Проектирование связей между классами Определение ассоциаций между классами • Все ассоциации между классами должны тщательно продуманы. • Многие ассоциации перейдут в проектную модель непосредственно из модели анализа, • Большой набор ассоциаций вводится в связи – ограничений реализации или – желания повторно использовать код. • Новые ассоциации модели проектирования необходимо проверять наиболее внимательно: – некоторая степень связанности хороша и необходима. • Допускается высокая связанность в рамках подсистемы, поскольку это указывает на сцепленность (высокую связность) компонента. • Нарушают архитектуру только многочисленные связи между подсистемами. – Необходимо активно стремиться к сокращению подобной связанности. Степень связанности разных отношений классов • Все виды связанности можно упорядочить по степени убывания следующим образом: 1. 2. 3. 4. Наследование (наиболее строгая связанность). Композиция Агрегирование Ассоциация Наследование • При проектировании наследование играет намного более важную роль, чем при анализе. • В анализе наследование использовалось, только в том случае, если между классами анализа имело место четкое и явно выраженное отношение «является» («is a»). • Однако при проектировании наследование может применяться в тактических целях для повторного использования кода. • Это совсем другой метод, т.к. наследование фактически используется для упрощения реализации дочернего класса, а не для описания бизнесотношения между родителем и потомком. Сравнение агрегации и наследования • Наследование – очень мощный метод. – Оно является ключевым механизмом формирования полиморфизма в строго типизированных языках программирования, таких как Java, C# и C++. • Однако неопытные ОО проектировщики и программисты часто используют его неправильно. • Необходимо понимать, что наследование имеет некоторые нежелательные характеристики: – Наследование – самая строгая форма связанности классов. – Это самая строгая из возможных форма связанности двух или более классов. • В иерархии классов будет плохая инкапсуляция. – связано с тем, что изменения базового класса передаются вниз по иерархии и приводят к изменениям всех подклассов. • Такое явление называется проблемой «хрупкости базового класса», когда изменения базового класса имеют огромное влияние на другие классы системы. • Во всех широко используемых ОО языках программирования отношения наследования постоянны во время выполнения. – Во время выполнения, можно изменять иерархии агрегации и композиции (создавая и уничтожая объекты), но иерархии наследования остаются неизменными. • Это делает наследование самым жестким типом отношений между классами. Пример • Задача моделирования сотрудников организации: есть сотрудник, которые могут иметь разные должности. – Решение выполненное неопытным разработчиком. • Имеется смысловая (семантическая) ошибка. – служащий (Employee) это • именно сама должность (Job) • или указание на то, что служащий занимает некоторую должность? • При использовании агрегации получаем правильный смысл: – у служащего (Employee) есть должность (Job). • При такой более гибкой модели у служащих при необходимости может быть несколько должностей. • Подклассы всегда должны представлять «особую разновидность чего-либо», а не «выполняемую роль». Сравнение наследования и реализации интерфейса • При наследовании класс получает: – интерфейс – открытые операции базовых классов; – реализацию – атрибуты, отношения, защищенные и закрытые операции базовых классов. • При реализации интерфейса класс получает: – интерфейс – набор открытых операций, атрибутов и отношений, не имеющих реализации. • У наследования и реализации интерфейса есть что-то общее, поскольку оба этих механизма обеспечивают возможность описания контракта, который должен быть реализован подклассами. – Однако семантика и применение этих двух методов совершенно разные. Рекомендация • В начале использования ОО подхода наследование часто считали основным механизмом многократного использования. • Однако разработчики выявили появление неприемлемых ограничений, накладываемых наследованием. • В связи с этим в настоящее время широкое применение наследования не рекомендуется. • Наследование должно использоваться только тогда, когда речь идет о наследовании от суперкласса некоторых деталей реализации (операций, атрибутов, отношений). – Это одна из разновидностей многократного использования. Реализация интерфейса • Реализация интерфейса полезна везде, где необходимо определить контракт, но без наследования деталей реализации. • Реализация интерфейса фактически не обеспечивает повторного использования кода, но – предоставляет точный способ описания контрактов и – гарантирует их выполнение классами реализации. • Т.к. в реализации интерфейса ничего не наследуется, это более гибкий и надежный способ проектирования, чем наследование. Уточнение отношений, выявленных на этапе анализе Отношения этапа проектирования • При переходе к проектированию необходимо уточнить отношения между классами анализа и превратить их в отношения между проектными классами. • Многие из выявленных при анализе отношений не могут быть реализованы непосредственно, как они описаны, их надо специально подготовить. – Например, ни один из широко распространенных ОО языков программирования не поддерживает двунаправленные ассоциации, классы-ассоциации или ассоциации «многие-ко-многим». • При создании проектной модели, необходимо определить, как такие ассоциации должны быть реализованы. • Уточнение ассоциаций анализа до ассоциаций этапа проектирования включает несколько процедур: – уточнение ассоциаций до отношений агрегации или композиции в соответствующих случаях; – реализацию ассоциаций «один-ко-многим»; – реализацию ассоциаций «многие-к-одному»; – реализацию ассоциаций «многие-ко-многим»; – реализацию двунаправленных ассоциаций; – реализацию классов-ассоциаций. • Все ассоциации уровня проектирования должны обладать: – возможностью навигации; – кратностью на обоих концах. • У всех ассоциаций уровня проектирования должно быть указано имя ассоциации или имя роли, по крайней мере, на целевом конце. Агрегация и композиция • При проектировании отношение ассоциация можно уточнить до агрегации или более строгой формы агрегации – композиции (композитной агрегации), если ассоциация имеет соответствующую семантику. – Агрегация – это свободный тип отношения между объектами – как между компьютером и его периферийным оборудованием. – Композиция – это очень строгий тип отношения между объектами – как между деревом и его листьями. Пример агрегации • Пример агрегации: компьютер очень слабо взаимосвязан со своим периферийным оборудованием. – Периферийные устройства могут появляться и исчезать, могут совместно использоваться с другими компьютерами. – Они не «принадлежат» конкретному компьютеру. Пример композиции • Пример композиции: дерево тесно взаимосвязано со своими листьями. – Листья принадлежат только одному дереву, ими нельзя поделиться с другими деревьями, и когда дерево умирает, листья умирают вместе с ним. Семантика агрегации • Агрегация – это тип отношения «целое-часть», в котором агрегат образуется многими частями. • В отношении «целое-часть» один объект (целое) использует сервисы другого объекта (части). • По существу, целое является доминантной и управляющей стороной отношения, тогда как часть просто обслуживает запросы целого и, следовательно, играет более пассивную роль. – Если навигацию можно осуществлять только от целого к части, последняя даже не знает, что является частью целого. Пример агрегации • Из данного примера видно, что: – компьютер (класс Computer) может быть присоединен к 0 или более принтерам (класс Printer); – в любой момент времени принтер соединен с 0 или 1 компьютером; – в ходе времени конкретный принтер может использоваться многими компьютерами; – принтер может существовать, даже если не подключен ни к одному компьютеру; – принтер фактически не зависит от компьютера. Семантика агрегации • агрегат может существовать как независимо от частей, так и вместе с ними; • части могут существовать независимо от агрегата; • агрегат является в некотором смысле неполным в случае отсутствия некоторых частей; • части могут принадлежать одновременно нескольким агрегатам. Агрегация транзитивна • Транзитивность означает, что если C является частью B, и B является частью A, тогда C также является частью A. Агрегация асимметрична • Это означает, что объект никогда – ни прямо, ни косвенно – не может быть частью самого себя. • Это ограничивает способы использования агрегации в моделях. • В приведенном ниже примере показано, что объекты Product могут состоять из других объектов Product. – Здесь нет ошибки, т.к. это разные объекты, и ограничение асимметрии не нарушено. • Иногда может понадобиться смоделировать ситуацию, когда между объектами d и a существует связь, как показано на рисунке. • Такое может случиться, если объекту d необходимо осуществить обратный вызов и использовать некоторые сервисы объектаагрегата a. • Рефлексивная агрегация с классом Product не подходит, потому что согласно ограничению асимметрии для агрегации объект a не может быть частью самого себя ни прямо, ни косвенно. • Поэтому для обработки связи между объектами d и a необходимо использовать рефлексивную неуточненную ассоциацию (это уже не агрегация) класса Product с самим собой, как показано ниже. Ассоциация симметрична • Объект может быть ассоциирован с самим собой. • На приведенной схеме показан другой типичный пример агрегации. • Домашний компьютер (целое) может быть смоделирован как набор частей. • Эти части довольно слабо взаимосвязаны с целым. • Их можно переносить с компьютера на компьютер или использовать совместно с другими компьютерами, поэтому в этой модели применима семантика агрегации. • Согласно этой модели домашний компьютер можно рассматривать как совокупность следующих частей: – – – – – Mouse (мышь), Keyboard (клавиатура), CPU (центральный процессор), Monitor (монитор) и два объекта Speaker (колонка). • CPU, в свою очередь, может быть смоделирован как совокупность различных аппаратных компонентов, таких как – RAM (ОЗУ), – HardDrive (жесткий диск) – и т. д. Семантика композиции • Композиция это более строгая форма агрегации. • Она имеет сходную (но более строгую) семантику. • Как и агрегация, это отношение «целое-часть», являющееся как транзитивным, так и асимметричным. • Ключевое различие между агрегацией и композицией в том, что в композиции у частей нет независимой жизни вне целого. • В композиции каждая часть принадлежит максимум одному и только одному целому, – тогда как при агрегации часть может совместно использоваться несколькими целыми. Пример композиции • В примере объекты Button (кнопка) не могут существовать независимо от владеющего ими объекта Mouse. • Если уничтожается объект Mouse, уничтожаются и принадлежащие ему объекты Button, потому что они являются его неотъемлемой частью. • Каждый объект Button может принадлежать только одному объекту Mouse. • Так же и листья на деревьях – жизнь листа определяется жизнью дерева, и лист может принадлежать только одному дереву. Семантика композиции • одновременно части могут принадлежать только одному композиту – совместное владение частями невозможно; • композит обладает исключительной ответственностью за все свои части; – он отвечает за их создание и уничтожение; • композит может высвобождать части, передавая ответственность за них другому объекту; • в случае уничтожения композита он должен или уничтожить все свои части, или передать ответственность за них другому объекту. • Композитный объект обладает полной ответственностью за жизненный цикл и управление своими частями. – при создании он часто создает и свои части; – при уничтожении он должен • уничтожить все свои части или • организовать их передачу другому композиту. • Для рефлексивной агрегации могут быть иерархии, и сети рефлексивной агрегации, • Для рефлексивной композиции возможны только иерархии. Композиция и атрибуты • Семантика композиции очень похожа на семантику атрибутов. – жизненный цикл в обоих случаях контролируется владельцами. – части, и атрибуты не могут независимо существовать вне своих владельцев. • Фактически, атрибуты – это точный эквивалент отношения композиции между классом композита и классом атрибута. Когда использовать композицию и атрибуты 1. Типом атрибута может быть простой тип данных. – В некоторых ОО языках программирования (например, C++ и Java), есть простые типы (например, int и double), которые не являются классами. – Простые типы можно моделировать как классы (с использованием стереотипа «primitive»), но это сильно загромождает модель. – Простые типы всегда должны моделироваться как атрибуты. 2. Существуют определенные, широко используемые вспомогательные классы, такие как Time, Date и String. – Если каждый раз моделировать эти классы с помощью отношения композиции, то очень скоро модели становятся абсолютно непонятными. – Намного лучше моделировать такие классы как атрибуты. Порядок уточнения отношения уровня анализа • При анализе использовались простые ассоциации без какого-либо подробного рассмотрения семантики отношения (или того, каким образом отношение должно быть реализовано). • Однако при проектировании необходимо всегда пытаться достичь максимальной конкретизации и уточнить ассоциации до одного из отношений агрегации везде, где это возможно. • Фактически ассоциация должна использоваться в проектировании, только в том случае, если схема агрегации образуется цикл. • Такая ситуация встречается редко, поэтому большинство аналитических ассоциаций превращаются или в агрегацию, или в композицию. • Ассоциации этапа анализа должны быть уточнены до одного из отношений агрегации везде, где это возможно. • После того как принято решение о применении агрегации или композиции, необходимо действовать следующим образом: 1. добавить в ассоциации кратности и имена ролей, если они отсутствуют; 2. выбрать, какой конец ассоциации является целым, а какой – частью; • посмотреть на кратность связи со стороны целого; если это «0..1» или 1, вероятно, можно использовать композицию; • в противном случае должна использоваться агрегация; 3. добавить возможность навигации от целого к части – • ассоциации уровня проектирования должны быть однонаправленными. Ассоциации «один-к-одному» • Практически всегда ассоциация «один-к-одному» превращается в композицию. • По сути, ассоциация «один-к-одному» подразумевает настолько строгое отношение между двумя классами, что стоит рассмотреть возможность их объединения в один класс без нарушения правил проектирования. • Если классы нельзя объединить, отношение «один-кодному» уточняется до композиции, как показано на рис. • Можно рассмотреть возможность превращения PartyIdentifier (идентификатор команды) в атрибут класса Party (команда) – если PartyIdentifier не является особо важным классом. • Упрощает диаграмму, но имеет и недостаток: – нельзя показать атрибуты или операции, принадлежащие классу PartyIdentifier. Ассоциации «многие-к-одному» • Если со стороны целого кратность равна «много», то – композиция становится невозможной, потому что часть используется совместно многими целыми. – возможна агрегация. • Необходимо выполнить проверку на наличие циклов в схеме агрегации. • Если циклов в ассоциации «многие-к-одному» не обнаружены, то ассоциацию «многие-к-одному» этапа анализа можно уточнять до агрегации. • Ассоциации «многие-к-одному» подразумевают агрегацию, если в схеме агрегации нет цикла. Ассоциации «многие-к-одному» • Если циклов в ассоциации «многие-к-одному» не обнаружены, то ассоциацию «многие-к-одному» этапа анализа можно уточнять до агрегации, как показано на рис. – один объект Currency (валюта) совместно используется многими объектами Money (деньги). – правильно отражает отношение между деньгами и валютой: деньги – это сумма в некоторой валюте. Ассоциации «один-ко-многим» • В ассоциации «один-ко-многим» со стороны «части» имеется коллекция объектов. • Для реализации такого отношения, необходимо использовать: – поддержку коллекций, предоставляемую языком реализации; – или классы-коллекции. • Большинство ОО языков программирования имеют минимальную встроенную поддержку коллекций объектов. • В основном, большинство языков программирования предлагают только массивы: – Преимуществом встроенных массивов является их высокая производительность. – Их недостаток малая гибкостью в сравнении с другими типами коллекций. • Классы-коллекции обычно обладают намного большей мощью и гибкостью, чем массивы. • Они предлагают разнообразные семантики, в которых массив является лишь одним из возможных вариантов. Коллекции • «Класс-коллекция» – это класс, экземпляры которого предназначены для управления наборами других объектов. • В большинстве языков программирования есть стандартные библиотеки классовколлекций (и других утилит). • Одним из ключей к отличному ОО проектированию и реализации является совершенное владение «классамиколлекций». Операции классов-коллекций • У всех таких классов есть операции для: 1. добавления объектов в коллекцию; 2. удаления объектов из коллекции; 3. извлечения ссылки на объект, находящийся в коллекции; 4. обход коллекции, т. е. проход по коллекции от первого объекта до последнего. • Существует много типов коллекций, поразному обрабатывающих коллекции объектов. • Важным аспектом ОО проектирования и реализации является правильный выбор типа коллекции. Пример использования коллекции • На рис. показана ассоциация один-ко-многим уровня анализа, реализованная с помощью класса-коллекции Vector (класс стандартной библиотеки Java java.util). • Как правило, между целым (классом Order (заказ)) и классом Vector устанавливается отношение композиции, поскольку Vector обычно является всего лишь частью реализации целого и не может существовать вне него. • Однако между классом Vector и его частями (OrderLine (строка заказа)) может существовать отношение агрегации или композиции. • Если целое несет ответственность за жизненный цикл частей, как в данном примере, можно использовать композицию. • В противном случае должна использоваться агрегация. • С точки зрения моделирования с использованием коллекций существуют следующие основные способы: 1. Явное моделирование «класса-коллекции». 2. Задание конкретного «класса-коллекций» для реализации ассоциации «один-ко-многим». 3. Указание использования коллекций, но без указания конкретного класса реализации. 4. Уточнение отношения «один-ко-многим» до «классов-коллекций» не выполняется – решение этой задачи передается программистам. 1. Явное моделирование класса-коллекции • Его преимущество в чрезвычайной детализации, однако есть и большой недостаток – «загроможденность» проектной модели. • Если ассоциация «один-ко-многим» заменяется «классомколлекции», модель быстро становится очень раздутой. • Выбор класса-коллекции обычно является тактическим решением реализации, и право это сделать можно передать программистам. • Рекомендуется заменять ассоциации «один-ко-многим» конкретными «классами-коллекций», только если выбор коллекции является стратегически важным. 2. Задание конкретного «класса-коллекций» для реализации ассоциации «один-ко-многим» • Многие инструменты моделирования, генерирующие код, позволяют назначать конкретный «классколлекции» для каждой ассоциации «один-комногим». • Обычно это осуществляется путем добавления в ассоциацию помеченных значений, определяющих свойства генерации кода для данного отношения. • Пример показан на схеме: на соответствующем конце отношения указано свойство {Vector}. – используется только именная часть помеченного значения – часть «значение» в данном случае является излишней. 3. Указание использования коллекций, но без указания конкретного класса реализации • Используемый тип коллекции – часто тактическое, а не стратегическое решение, которое может быть принято программистами во время реализации. • Этот вариант хорош тем, что сохраняется лаконичность модели, и программистам могут быть предоставлены подсказки по поводу того, какой «класс-коллекции» должен использоваться. • Однако такой подход обычно исключает автоматическую генерацию кода. UML обозначения для коллекций • UML предоставляет стандартные свойства, которые могут применяться к кратностям для обозначения требуемой семантики коллекции. Свойство Семантика {ordered} Существует строгий порядок расположения элементов коллекции. {unordered} Элементы в коллекции располагаются в произвольном порядке. {unique} Все элементы коллекции уникальны – один и тот же объект появляется в коллекции максимум один раз. {nonunique} В коллекции допускается дублирование элементов. • Упорядоченность - определяет, как располагаются элементы в коллекции: в строгом порядке относительно друг друга или нет. • Уникальность - определяет единичность каждого объекта коллекции. • Для отношения один-ко-многим по умолчанию применяется семантика {unordered, unique} ({неупорядоченный, уникальный}). • Сочетания свойств упорядочения и уникальности создают набор коллекций: Свойство Коллекция OCL {unordered, nonunique} Bag (мультимножество) {unordered, unique} Set (множество) {ordered, unique} OrderedSet (упорядоченное множество) {ordered, nonunique} Sequence (последовательность) Конкретизация отношений • Некоторые типы отношений являются исключительно элементами анализа и не поддерживаются напрямую ни одним из широко используемых ОО языков программирования. • Процесс реализации таких отношений уровня анализа называют конкретизацией (reification) (т. е. превращение в нечто конкретное). • Конкретизации подвергаются следующие отношения уровня анализа: – ассоциации «многие-ко-многим»; – двунаправленные ассоциации; – «классы-ассоциации». Ассоциации «многие-ко-многим» • Ни один из широко используемых ОО языков программирования не поддерживает напрямую ассоциации «многие-ко-многим». • В связи с этим такие ассоциации необходимо конкретизировать в обычные классы, отношения агрегации, композиции и зависимости. • При анализе такие вопросы, как владение и навигация, могли бы оставаться неясными, но в проектировании такая неопределенность невозможна. • Это тот случай, когда сначала надо решить, какая из сторон ассоциации «многие-ко-многим» является целым, а затем применять соответственно агрегацию или композицию. Пример ассоциации «многие-ко-многим» • В данном примере отношение allocation (распределение) было конкретизировано в класс Allocation. • Это превращает ассоциацию «многие-комногим» в два отношения агрегации. • Исходя из требований, предъявляемых к системе, было принято решение, что Resource (ресурс) – это целое. • Система главным образом занимается управлением потоками работ, ассоциированными с Resource, т. е. является «ресурсо-центричной». • Однако если бы система была «задачецентричной», целым был бы сделан объект Task (задача), что изменило бы направление отношений, представленных на рисунке. • Также было решено возложить ответственность за жизненный цикл объектов Allocation на Resource, и поэтому используется отношение композиции. • Если система пытается представить обе точки зрения, ее можно было бы назвать ориентированной на распределение ресурсов. • Тогда был бы введен новый объект (возможно, AllocationManager (менеджер распределения)), обслуживающий список объектов Allocation, каждый объект которого указывает как на объект Resource, так и на объект Task. Двунаправленные ассоциации • Часто необходимо смоделировать обстоятельства, в которых – объект а класса А использует сервисы объекта b класса В, и – объекту b необходимо делать обратный вызов и использовать сервисы объекта а. • Например: управление GUI Window с одним или более объектами Button, где – каждому объекту Button надо выполнять обратный вызов и – использовать сервисы Window, которому они принадлежат. Конкретизация двунаправленной ассоциации • При анализе все просто – такая ситуация моделируется как единственная двунаправленная ассоциация. • Однако ни один из широко используемых ОО языков программирования реально не поддерживает двунаправленные ассоциации. • Поэтому при проектировании такая ассоциация должна быть конкретизирована в две однонаправленные ассоциации или зависимости, как показано на рис. • При моделировании обратных вызовов необходимо помнить об асимметрии агрегации и композиции – объект никогда – ни прямо, ни косвенно – не может быть частью самого себя. • Это значит, что если класс А имеет отношение агрегации или композиции с классом В, обратный вызов от В к А должен быть смоделирован как не конкретизированная ассоциация. • Если бы между B и A было применено отношение агрегации, объект b был бы частью (через композицию или агрегацию) объекта а, и объект а был бы частью (через агрегацию) объекта b. • Такое замкнутое владение, конечно же, нарушает асимметричность агрегации. • Двунаправленные ассоциации также имеют место тогда, когда целое передает ссылку на себя в качестве параметра одной из операций части или когда часть в одной из своих операций создает экземпляр целого. • В этих случаях необходимо использовать отношение зависимости от части к целому, а не ассоциацию. • Если бы между B и A было применено отношение агрегации, – объект b был бы частью (через композицию или агрегацию) объекта а, и – объект а был бы частью (через агрегацию) объекта b. • Такое замкнутое владение, нарушает асимметричность агрегации. • Двунаправленные ассоциации также имеют место тогда, когда целое передает ссылку на себя в качестве параметра одной из операций части или когда часть в одной из своих операций создает экземпляр целого. • В этих случаях необходимо использовать отношение зависимости от части к целому, а не ассоциацию. «Классы-ассоциации» • «Классы-ассоциации» – это объекты которые используются только на этапе анализа; они напрямую не поддерживаются ни одним из широко используемых ОО языков программирования. • Таким образом, они не имеют прямого аналога на этапе проектирования и должны быть удалены из проектной модели. Конкретизация «классов-ассоциаций» • «Класс-ассоциация» конкретизируется в обычный класс, а для отражения его семантики используется сочетание ассоциации, агрегации, композиции или даже зависимости. • Это может потребовать наложения ограничений на модель. • Принимается решение, какая из сторон ассоциации является целым, и соответственно этому используется композиция, агрегация и возможность навигации. Пример класса-ассоциации • При конкретизации класса-ассоциации теряется его семантика, которая гласит, что объекты на каждом конце класса-ассоциации должны формировать уникальную пару. • Однако, добавив примечание, содержащее соответствующее ограничение, эту семантику можно задать. Шаблоны проектирования Шаблоны проектирования • В проектировании ПО часто встречаются проблемы, которые уже решались ранее в других проектах. • В связи с тем, что контексты, в которых данная проблема решалась, могут различаются – (другой тип приложения, другая платформа или другой язык программирования), – все обычно заканчивается повторением проектирования и реализации данного решения, – тем самым возникает ситуация «повторного изобретения колеса». • В этом случае разработчикам могут помочь, программные шаблоны, включая – архитектурные шаблоны и – шаблоны проектирования. • Они позволяют избежать ненужного повторного проектирования и реализации. • Понятие шаблона (pattern) впервые было предложено Christopher Alexander для разработки архитектуры зданий и описаны в его книге – «The Timeless Way of Building» (Alexander 1979). • «Любой паттерн описывает задачу, которая снова и снова возникает в нашей работе, а также принцип ее решения, причем таким образом, что это решение можно потом использовать миллион раз, ничего не изобретая заново» (Александр Кристофер, архитектор). • Такое определение верно и в отношении паттернов объектно-ориентированного проектирования. Понятие паттерна (шаблона) • При ООП решения описываются в терминах объектов и интерфейсов, а не стен и дверей, но в обоих случаях смысл паттерна - предложить решение определенной задачи в конкретном контексте. • Под паттернами ОО проектирования понимается описание взаимодействия объектов и классов, адаптированных для решения общей задачи проектирования в конкретном контексте. • В области ПО использование шаблонов проектирования было предложено и развито Gamma, Helms, Johnson и Vlissides в их книге «Design Patterns (1995)», в которой они описали 23 шаблона проектирования. – Э. Гамма, Р. Хелм, Р. Джонсон, Д. Влиссидес «Приемы объектноориентированного проектирования (Паттерны проектирования)», «ДМК Пресс», СПб, 2010, 368 с. Типы шаблонов • Шаблоны проектирования (design patterns) – Шаблон проектирования это небольшая взаимодействующих объектов. • Архитектурные шаблоны (architectural patterns). – Архитектурные шаблоны это шаблоны описывающие взаимодействие более крупных элементов, чем шаблоны проектирования. – Они предназначенные для определения структуры больших подсистем программной системы. • Шаблоны анализа (analysis patterns). – Fowler (2002) обнаружил сходства в ходе анализа приложений, разрабатываемых для разных предметных областей. – Он описал часто повторяющиеся шаблоны найденные в ОО анализе с помощью статических моделей, представленных в виде диаграмм классов. • Идиомы (idioms). Шаблоны • Шаблоны позволяют основываться на коллективном опыте квалифицированных инженеров по проектированию ПО (ТРПО). • Они фиксируют существующий, хорошозарекомендовавший себя опыт разработки ПО и помогает содействовать хорошим методам проектирования. • Каждый шаблон имеет дело с конкретной, многократно встречающейся проблемой в области проектирования и реализации ПО. • Шаблоны могут использоваться для создания архитектур ПО с конкретными свойствами. Каталог паттернов проектирования 1. Abstract Factory (абстрактная фабрика) – Предоставляет интерфейс для создания семейств, связанных между собой, или независимых объектов, конкретные классы которых неизвестны. 2. Adapter (адаптер) – Преобразует интерфейс класса в некоторый другой интерфейс, ожидаемый клиентами. – Обеспечивает совместную работу классов, которая была бы невозможна без данного паттерна из-за несовместимости интерфейсов. 3. Bridge (мост) – Отделяет абстракцию от реализации, благодаря чему появляется возможность независимо изменять то и другое. 4. Builder (строитель) – Отделяет конструирование сложного объекта от его представления, позволяя использовать один и тот же процесс конструирования для создания различных представлений. 5. Chain of Responsibility (цепочка обязанностей) – Можно избежать жесткой зависимости отправителя запроса от его получателя, при этом запросом начинает обрабатываться один из нескольких объектов. – Объекты-получатели связываются в цепочку, и запрос передается по цепочке, пока какой-то объект его не обработает. Каталог паттернов проектирования 6. Command (команда) – Инкапсулирует запрос в виде объекта, позволяя тем самым параметризовывать клиентов типом запроса, устанавливать очередность запросов, протоколировать их и поддерживать отмену выполнения операций. 7. Composite (компоновщик) – Группирует объекты в древовидные структуры для представления иерархий типа «часть-целое». – Позволяет клиентам работать с единичными объектами так же, как с группами объектов. 8. Decorator (декоратор) (173) – Динамически возлагает на объект новые функции. – Применяются для расширения имеющейся функциональности и являются гибкой альтернативой порождению подклассов. 9. Facade (фасад) (183) – Предоставляет унифицированный интерфейс к множеству интерфейсов в некоторой подсистеме. – Определяет интерфейс более высокого уровня, облегчающий работу с подсистемой. 10. Factory Method (фабричный метод) – Определяет интерфейс для создания объектов, при этом выбранный класс инстанцируется подклассами. 11. Flyweight (приспособленец) – Использует разделение для эффективной поддержки большого числа мелких объектов. 12. Interpreter (интерпретатор) – Для заданного языка определяет представление его грамматики, а также интерпретатор предложений языка, использующий это представление. 13. Iterator (итератор) – Дает возможность последовательно обойти все элементы составного объекта, не раскрывая его внутреннего представления. 14. Mediator (посредник) – Определяет объект, в котором инкапсулировано знание о том, как взаимодействуют объекты из некоторого множества. – Способствует уменьшению числа связей между объектами, позволяя им работать без явных ссылок друг на друга. – Это, в свою очередь, дает возможность независимо изменять схему взаимодействия. 15. Memento (хранитель) – Позволяет, не нарушая инкапсуляции, получить и сохранить во внешней памяти внутреннее состояние объекта, чтобы позже объект можно было восстановить точно в таком же состоянии. 16. Observer (наблюдатель) – Определяет между объектами зависимость типа один-комногим, так что при изменении состоянии одного объекта все зависящие от него получают извещение и автоматически обновляются. 17. Prototype (прототип) – Описывает виды создаваемых объектов с помощью прототипа и создает новые объекты путем его копирования. 18. Proxy (заместитель) – Подменяет другой объект для контроля доступа к нему. 19. Singleton (одиночка) – Гарантирует, что некоторый класс может иметь только один экземпляр, и предоставляет глобальную точку доступа к нему. 20. State (состояние) – Позволяет объекту варьировать свое поведение при изменении внутреннего состояния. При этом создается впечатление, что поменялся класс объекта. 21. Strategy (стратегия) – Определяет семейство алгоритмов, инкапсулируя их все и позволяя подставлять один вместо другого. Можно менять алгоритм независимо от клиента, который им пользуется. 22. Template Method (шаблонный метод) – Определяет скелет алгоритма, перекладывая ответственность за некоторые его шаги на подклассы. Позволяет подклассам переопределять шаги алгоритма, не меняя его общей структуры. 23. Visitor (посетитель) – Представляет операцию, которую надо выполнить над элементами объекта. Позволяет определить новую операцию, не меняя классы элементов, к которым он применяется.