Задача: Определение элементов проекта
Это задание описывает способы определения подсистем, классов, интерфейсов, событий и сигналов.
Дисциплины: Анализ и проектирование
Назначение
  • Проанализировать взаимодействие аналитических классов и определить элементы модели проектирования
Взаимосвязи
Основное описание

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

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

При проектировании также выделяются:

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

Более точные описания позволяют рассмотреть различные аспекты проектирования:

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

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

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

Разделение задач и вопросов ведет к упрощению процесса проектирования и созданию более ясного решения.

Если требуется возможность отслеживания поведения подсистем, то это требование следует внести в документацию в ходе выполнения задания.  Дополнительная информация о документировании взаимодействия между моделью проектирования и другими моделями содержится в документе Рекомендация: Модель проектирования.

 Представление с помощью UML 1.x

В соответствии с терминологией UML 1.5 подсистема - это особый вид группы, общедоступными элементами которой являются только интерфейсы. Интерфейс является средством инкапсуляции, скрывающим внутреннее строение подсистемы от других элементов модели. Подсистема отличается от "обычных" групп, которые представляют собой не ограниченные семантическими правилами контейнеры элементов модели; подсистема является частным случаем группы, обладающим некоторыми свойствами класса.

В RUP капсулы представляются с использованием нотации UML 1.5. В большинстве случаев можно применять UML 2.0, используя концепцию структурированного класса.

Дополнительная информация содержится в документе Различия между UML 1.x и UML 2.0.

Шаги
Определить события и сигналы
Цель Определить внешние и внутренние события и сигналы, на которые система должна реагировать. 

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

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

Наиболее существенные характеристики события:

  • внутреннее/внешнее - Является событие внутренним или внешним?
  • приоритет - требуется ли для обработки этого события приостанавливать другие процессы?
  • частота - Как часто событие происходит?
  • распределение частот - Событие происходит через регулярные интервалы времени, или наблюдаются определенные пики?
  • требования к ответу - Насколько быстро система должна отреагировать на событие? (возможно, следует указать среднее и максимальное допустимое значение)
  • род - Это событие является вызовом, наступлением определенного срока, сигналом либо обнаруженным изменением (определения содержатся в документе Концепция: События и сигналы)?

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

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

Определить классы, активные классы и подсистемы
Цель Преобразовать аналитические классы в соответствующие элементы модели проектирования 

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

В процессе определения классов их следует разделять по группам проектирования, что облегчает задачи создания и управления конфигурациями. Дополнительная информация о составлении групп содержится в документе Рекомендация по рабочему продукту: Группа проектирования.

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

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

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

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

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

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

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

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

В системах реального времени вместо активных классов следует использовать капсулы: если в соответствии с вышеприведенными правилами была определена потребность в активном классе, следует заменить его на капсулу.

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

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

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

Определите интерфейсы подсистем
Цель Определить элементы проектирования, которые будут представлять элементы системы. 

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

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

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

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

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

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

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

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

Определите протоколы капсул

Цель

Определить элементы проектирования, которые будут представлять элементы системы (только для систем реального времени).

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

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

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

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

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

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

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


Дополнительные сведения