Разработка корпоративной информационной системы на основе объектно-ориентированного подхода

ВОЛЖСКИЙ  УНИВЕРСИТЕТ ИМ. ТАТИЩЕВА (ИНСТИТУТ)

КАФЕДРА «Промышленная информатика»













УТВЕРЖДАЮ

Проректор по учебной работе

__________ Никифорова Е.В.

от «____» _________ 2004 г.









РАЗРАБОТКА КОРПОРАТИВНЫХ ИНФОРМАЦИОННЫХ СИСТЕМ НА ОСНОВЕ ОБЪЕКТНО-ОРИЕНТИРОВАННОГО ПОДХОДА



Учебное пособие



по дисциплине «Корпоративные информационные системы»

для студентов специальности 071900 «Информационные системы»



дневного и заочного отделения

























Тольятти 2004


Куралесова Н.О. Разработка корпоративной информационной системы на основе объектно-ориентированного подхода. Учебное пособие. –Тольятти: Волжский университет им.В.Н.Татищева, 2004











Рецензент: к.т.н., доцент кафедры «Информатика и системы управления»

		Трубачева С.И.



Рассмотрено и утверждено на заседании кафедры 

«Промышленная информатика»

«___»_______________2004 года

Протокол № ____ от «____» __________ 2004 г.




Содержание



1. Разработка модели автоматизации системы банковского обслуживания

1.1. Анализ требований и предварительное проектирование

1.2. Построение объектной модели

1.2.1. Определение объектов и классов

1.2.2. Подготовка словаря данных

1.2.3. Определение зависимостей

1.2.4. Уточнение атрибутов

1.2.5. Организация системы классов с использованием наследования

1.2.6. Усовершенствование модели

1.2.7. Определение подсистем

1.2.8. Интерфейсы и окружения

1.3. Динамическая модель системы или подсистемы

1.4. Функциональная модель подсистемы

1.4.1. Диаграммы потоков данных

1.4.2. Описание операций

1.4.3. Ограничения

2. Конструирование системы

2.1. Разработка архитектуры системы

2.1.1. Разбиение системы на модули

2.1.2. Выявление асинхронного параллелизма

2.1.3. Распределение модулей и подсистем по процессорам и задачам

2.1.4. Управление хранилищами данных

2.1.5. Реализация управления программным обеспечением

2.1.6. Пограничные ситуации

2.1.7. Архитектур прикладных систем

2.2. Разработка объектов

2.2.1. Совместное рассмотрение трех моделей

2.2.2. Разработка алгоритмов, реализующих полученные операции

2.2.3. Оптимизация разработки

2.2.4. Реализация управления

2.2.5. Уточнение наследования классов

2.2.6. Разработка зависимостей

3. Реализация объектно-ориентированного проекта








1. Разработка модели автоматизации системы банковского обслуживания

1.1. Анализ требований и предварительное проектирование

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

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

Компьютер банка поддерживает счета клиентов, т.е. хранит их в своей базе данных и выполняет проводки над этими счетами по запросам с БМ (удаленная проводка) или с кассовых терминалов (проводка кассира, данные о которой вводятся кассиром). 





Счет

Счет

Счет

БМ_1

БМ_N

…

Центральный компьютер

Компьютер банка

Компьютер банка













Рисунок 1.1 – Схема объектов автоматизации



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

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

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

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



1.2. Построение объектной модели

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

Для построения объектной модели рассматриваемой системы нам необходимо выполнить: 

определение объектов и классов; 

подготовка словаря данных; 

определение зависимостей между объектами; 

определение атрибутов объектов и связей; 

организация и упрощение классов при использовании наследования; 

дальнейшее исследование и усовершенствование модели. 



1.2.1. Определение объектов и классов

Анализируя постановку задачи, можно выделить возможные классы, сопоставив их существительным, упомянутым в ее предварительной формулировке; получится следующий список возможных имен классов (в алфавитном порядке): 

БМ (банкомат)

Кассир

Программное обеспечение

Банк

Кассовый терминал

Система

Банковская_сеть

Квитанция

Проверка_безопасности

Данные_проводки

Клиент

Служба_ведения_записей

Данные_счета

Компьютер_банка

Счет

Деньги

Консорциум

Цена

Доступ

Пользователь

Центральный_компьютер

Карточка

Проводка





Исследуем этот список, исключая из него имена классов: 

избыточные классы: т.к. клиент и пользователь означают одно и то же понятие; для банковской системы более естественно оставить класс клиент; 

нерелевантные классы: таким классом является класс - цена (этот класс не имеет непосредственного отношения к работе банковской сети); 

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

атрибуты: данные проводки, данные счета, деньги (имеются в виду реальные деньги, выдаваемые клиенту кассиром или банкоматом, либо принимаемые кассиром), квитанция (выдается клиенту вместе с деньгами) более естественно иметь в качестве атрибутов; 

реализационные конструкции: например, программное_обеспечение и доступ. 

После исключения лишних имен возможных классов получаем следующий список: БМ (банкомат), Консорциум, Банк, Кассовый терминал, Центральный компьютер, Компьютер банка, Карточка, Счет, Проводка, Клиент, Кассир.



1.2.2. Подготовка словаря данных

Приведем словарь данных, содержащий определения классов, используемых в проекте.

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

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

Карточка - пластиковая карточка, врученная банком своему клиенту, которая санкционирует доступ к счетам через сеть БМ (банкоматов). Каждая карточка содержит код банка и номер карточки, закодированные в соответствии с национальными стандартами на банковские карточки. Код_банка однозначно идентифицирует банк внутри консорциума. Номер_карточки определяет счета, к которым карточка имеет доступ. Карточка не обязательно обеспечивает доступ ко всем счетам клиента. Каждой карточкой может владеть только один клиент, но у нее может существовать несколько копий, так что необходимо рассмотреть возможность одновременного использования одной и той же карточки с разных БМ (банкоматов). 

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

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

Клиент - держатель одного или нескольких счетов в банке. Клиент может состоять из одного или нескольких лиц, или организаций. То же самое лицо, держащее счет и в другом банке рассматривается как другой клиент. 

Компьютер_банка - компьютер, принадлежащий банку, который взаимодействует с сетью БМ (банкоматов) и собственными кассовыми_терминалами банка. Банк может иметь свою внутреннюю компьютерную сеть для обработки счетов, но здесь мы рассматриваем только тот компьютер_банка, который взаимодействует с сетью БМ. 

Консорциум - объединение банков, которое обеспечивает работу сети БМ (банкоматов). Сеть передает в консорциум проводки банков. 

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

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

Центральный_компьютер - компьютер, принадлежащий консорциуму, который распределяет проводки и их результаты между БМ (банкоматами) и компьютерами_банков. Центральный_компьютер проверяет коды банков, но не выполняет проводок самостоятельно.



1.2.3. Определение зависимостей

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

Глагольные обороты (явные и неявные): 

Банковская сеть включает кассиров и БМ

Консорциум распределяет результаты проводок по БМ

Банк владеет компьютером банка 

Компьютер банка поддерживает счета 

Банк владеет кассовыми терминалами 

Кассовый терминал взаимодействует с компьютером банка 

Кассир вводит проводку над счетом 

БМ взаимодействуют с центральным компьютером во время проводки 

Центральный компьютер взаимодействует с компьютером банка 

БМ принимает карточку 

БМ общается с пользователем 

БМ выдает наличные деньги 

БМ печатает квитанции 

Система регулирует коллективный доступ 

Банк предоставляет программное обеспечение 

Консорциум состоит из банков 

Консорциум владеет центральным компьютером 

Система обеспечивает протоколирование 

Система обеспечивает безопасность 

Клиенты имеют карточки 

Карточка обеспечивает доступ к счету 

В банке служат кассиры 

Затем исключаем ненужные или неправильные зависимости: 

зависимости между исключенными классами: исключаются следующие зависимости: Банковская сеть включает кассиров и БМ (класс банковская_сеть исключен), БМ печатает квитанции (класс квитанция исключен), БМ выдает наличные деньги (класс деньги исключен), Система обеспечивает протоколирование проводок (класс служба_ведения_записей исключен), Система обеспечивает безопасность ведения счетов (класс служба_безопасности исключен), Банки предоставляют программное обеспечение (класс программное_обеспечение исключен); 

нерелевантные зависимости и зависимости, связанные с реализацией: зависимость «Система регулирует коллективный доступ» исключается как связанная с реализацией; 

действия описываются такими зависимостями как «БМ принимает карточку» и «БМ общается с пользователем»; мы исключаем эти зависимости; 

тренарные зависимости: зависимость «Кассир вводит проводку над счетом» раскладывается на две бинарные зависимости «Кассир вводит проводку» и «Проводка относится к счету». Зависимость «БМ взаимодействуют с центральным компьютером во время проводки» раскладывается на «БМ взаимодействуют с центральным компьютером» и «Проводка начинается с БМ»; 

производные зависимости: зависимость «Консорциум распределяет БМ» является следствием зависимостей «Консорциум владеет центральным компьютером» и «БМ взаимодействуют с центральным компьютером». 

Удалив избыточные зависимости, получим следующий список зависимостей: 

Банк владеет компьютером банка 

Компьютер банка поддерживает счета 

Банк владеет кассовыми терминалами 

Кассовый терминал взаимодействует с компьютером банка 

Кассир вводит проводку 

Проводка относится к счету 

БМ взаимодействуют с центральным компьютером 

Проводка начинается с БМ 

Центральный компьютер взаимодействует с компьютером банка

Консорциум состоит из банков 

Консорциум владеет центральным компьютером 

Клиенты имеют карточки 

Карточка обеспечивает доступ к счету 

В банке служат кассиры 

Уточним семантику оставшихся зависимостей следующим образом: 

переименуем неверно названные зависимости, чтобы смысл их стал более понятен; так зависимость «Компьютер_банка поддерживает счета» удобнее заменить зависимостью «Банк держит счета». 

имена ролей можно не использовать, например, зависимость «БМ взаимодействуют с центральным компьютером»; 

неучтенные зависимости: «Проводка начинается с кассового_терминала», «Клиенты имеют счета», «Проводка регистрируется карточкой» следует добавить в модель. 

После уточнения зависимостей можно составить начальную объектную диаграмму (рис. 1.2). 





Рисунок 1.2 -  Первая версия объектной диаграммы для банковской сети



1.2.4. Уточнение атрибутов

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

После внесения перечисленных изменений диаграмма примет вид, представленный на рис 1.3



1.2.5. Организация системы классов с использованием наследования

В рассматриваемом примере естественно определить суперклассы для объектов, определяющих различные терминалы: кассовый_терминал и БМ (банкомат), и для объектов, определяющих проводки: проводка_кассира и удаленная_проводка (с банкомата). 

Внеся соответствующие изменения, получим объектную диаграмму, представленную на рисунке 1.4. 



Рисунок 1.3 - Объектная диаграмма для банковской сети после уточнения атрибутов и добавления квалификаторов





Рисунок 1.4 - Объектная диаграмма для банковской с учетом наследования



1.2.6. Усовершенствование модели

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

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

Класс банк естественно объединить с классом компьютер_банка, а класс консорциум - с классом центральный_компьютер. 



Рисунок 1.5 - Окончательный вид объектной диаграммы для банковской сети



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



1.2.7. Определение подсистем

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

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

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

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

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

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

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

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

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





Рисунок 1.6 -  Объектная диаграмма банковской сети, в которой указан интерфейс с системным окружением





Рисунок 1.7 - Объектная диаграмма банковской сети и ее системного окружения



1.2.8. Интерфейсы и окружения

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

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

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

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

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





Рисунок 1.8. - Объектная диаграмма банковской сети после выделения подсистемы банк



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



1.3. Динамическая модель системы или подсистемы

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

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

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

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

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

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

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

Состояние определяет реакцию объекта на поступающее в него событие. Реакция объекта на событие может включать некоторое действие и/или перевод объекта в новое состояние. 

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

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

Диаграмма состояний связывает события и состояния. Смена состояния называется переходом. 

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

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

Активностью называется операция, связанная с каким-либо состоянием объекта (она выполняется, когда объект попадает в указанное состояние); выполнение активности требует определенного времени. Активность связана с состоянием, поэтому на диаграмме состояний она обозначается через «do: имя_активности» в узле, описывающем соответствующее состояние (рис.1.9). 





Рисунок 1.9 - Указание активностей и действий на диаграмме состояний



Действием называется мгновенная операция, связанная с событием: при возникновении события происходит не только переход объекта в новое состояние, но и выполняется действие, связанное с этим событием. 

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

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

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





Рисунок 1.10. - Передача события из одного объекта другому



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

Синхронизация используется и в случае, когда в каком-либо состоянии требуется параллельно выполнить несколько активностей. Рассмотрим устройство вывода БМ (рисунок 1.11). Оно одновременно (параллельно) выдает наличные деньги и карточку; обе эти операции можно рассматривать как составную активность, состоящую из двух параллельно работающих активностей (пунктирная линия на диаграмме состояний делит состояние на две области, в каждой из которых выполняется одна из указанных активностей). Разделение управления на два параллельных потока схематически показано в виде стрелки, которая разделяется на две: событие «готов» вызывает переход из состояния «установка» сразу в два параллельных под состояния: состояния «выдача» и «выбросить»; переход в следующее состояние происходит по двум событиям «деньги взяты» и «карточка взята»; если какое-либо из этих событий произойдет раньше другого, перехода все равно не будет, пока не произойдет и второе событие (в этом и состоит синхронизация). Из рассмотренного примера видно, что в различных состояниях может параллельно работать разное число процессов (активностей).



Рисунок 1.11 - Синхронизация в подсистеме



Построим динамическую модель банковской сети. Начальный сценарий: 

БМ просит клиента вставить карточку клиент вставляет карточку

БМ принимает карточку и читает ее номер

БМ просит ввести пароль клиент вводит "1234"

БМ передает номер и пароль в консорциум, консорциум проверяет номер и пароль, определяет код банка - "39" и сообщает БМ, что запрос принят

БМ просит клиента (с помощью меню на экране) выбрать вид проводки(снятие, вклад, перевод, запрос) клиент выбирает снятие

БМ спрашивает клиента какова требуемая сумма клиент вводит $100

БМ убеждается, что введенная сумма в пределах лимита и просит консорциум выполнить проводку, консорциум передает запрос в банк, банк выполняет проводку и возвращает новое значение баланса счета

БМ выдает сумму и просит клиента взять ее клиент берет деньги

БМ спрашивает, не нужно ли клиенту чего еще клиент вводит нет

БМ печатает счет, выдает карточку и просит клиента взять их клиент берет счет и карточку

БМ просит (другого) клиента ввести карточку.

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

БМ просит клиента вставить карточку, клиент вставляет карточку

БМ принимает карточку и читает ее номер

БМ просит ввести пароль, клиент вводит "9999."

БМ передает номер и пароль в консорциум; консорциум, проконсультировавшись с соответствующим банком, отвергает запрос

БМ сообщает, что пароль введен неверно, клиент вводит "1234."

БМ передает номер и пароль в консорциум, консорциум проверяет номер и пароль, определяет код банка - "39" и сообщает БМ, что запрос принят

БМ просит выбрать вид проводки, клиент выбирает снятие

БМ спрашивает, какова требуемая сумма клиент (раздумав брать деньги) набирает отмену

БМ выдает карточку и просит клиента взять ее  клиент берет карточку

БМ просит (другого) клиента вставить карточку.

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

Имея трассы событий, можно построить диаграммы состояний объектов проектируемой системы. Банковская сеть есть агрегация определенного числа параллельно и независимо работающих объектов четырех классов: консорциум, банк, БМ (банкомат) и клиент; поэтому состояние банковской сети определяется как кортеж состояний составляющих ее объектов: 1 объекта класса консорциум, b объектов класса банк, a объектов класса БМ (банкомат) и c объектов класса клиент (a, b, c - количество БМ, банков и клиентов сети соответственно). Классификация объектов, используемая при объектно-ориентированном подходе, позволяет вместо a+b+1 диаграмм состояний построить всего три (диаграммы состояний клиентов строить не нужно, так как их текущее состояние ясно и так). 

Построение диаграмм состояний начинается с привязки событий к объектам банковской сети (рисунок 1.13), являющимся источниками этих событий. Сначала рассматриваются нормальные события, потом исключительные события. Построение диаграммы состояний объекта (класса) может считаться законченным, когда диаграмма охватывает все рассматриваемые сценарии. Диаграммы состояний объектов классов БМ (рисунок 1.14), консорциум (рисунок 1.15) и банк (рисунок 1.16).





Рисунок 1.12 - Трасса событий в банковской сети





Рисунок 1.13 - Привязка событий к объектам банковской сети





Рисунок. 1.14 - Диаграмма состояний объектов класса БМ



Рисунок 1.15 - Диаграмма состояний объектов класса консорциум





Рисунок 1.16 - Диаграмма состояний объектов класса банк



1.4. Функциональная модель подсистемы

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



1.4.1. Диаграммы потоков данных

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

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

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





Рисунок. 1.17 - Примеры процессов



Процессы реализуются в виде методов (или их частей) и соответствуют операциям конкретных классов. 

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



Рисунок 1.18 - Потоки данных



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



Рисунок 1.19 - Активные объекты (экторы)



Хранилище данных - это пассивный объект в составе ДПД, в котором данные сохраняются для последующего доступа. Хранилище данных допускает доступ к хранимым в нем данным в порядке, отличном от того, в котором они были туда помещены. Агрегатные хранилища данных, как например, списки и таблицы, обеспечивают доступ к данным в порядке их поступления, либо по ключам. Примеры хранилищ данных приведены на рисунке 1.20. 



Рисунок 1.20 - Хранилища данных



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



Рисунок 1.21 - Поток управления



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

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



1.4.2. Описание операций

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

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

математические формулы; 

табличные функции: таблицы, сопоставляющие выходные значения входным; 

уравнения, связывающие входные и выходные значения; 

аксиоматическое определение операций с помощью пред- и пост-условий; 

таблицы принятия решений; 

псевдокод; 

естественный язык. 

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

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

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

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



1.4.3. Ограничения

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

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

определить входные и выходные значения; 

построить ДПД, показывающие функциональные зависимости; 

описать функции; 

описать ограничения; 

сформулировать критерии оптимизации; 

уточнить набор операций в объектной модели. 

Выполним все эти шаги, чтобы построить функциональную модель банковской сети (БМ). 

Начнем с определения входных и выходных значений. Эти значения являются параметрами событий между системой и окружающим ее миром. Входные и выходные значения банковской сети показаны на рисунке 1.22 (пунктирная линия показывает границу системы). 





Рисунок 1.22 -  Входные и выходные значения банковской сети



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

ДПД обычно строится по уровням. На верхнем уровне, как правило, показывают один единственный процесс, или, как в нашем примере (рисунок 1.23), процесс ввода, основной процесс вычисления требуемых значений и процесс вывода. Входные и выходные данные на этой диаграмме поставляются и потребляются внешними объектами (клиент, карточка). 



Рисунок 1.23 - Процессы верхнего уровня в системе обслуживания банковской сети



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



Рисунок 1.24 - ДПД процесса выполнить проводку в системе обслуживания банковской сети



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

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

После того как ДПД составлена, необходимо описание каждой функции из ДПД. Пример описания функции:

изменить_счет (счет, сумма, вид_проводки) -> деньги, квитанция

если сумма снимается и больше баланса счета,

то "отменить_проводку";

если сумма снимается и меньше баланса счета,

то "дебетовать_счет" и "выдать_деньги";

если сумма вносится на счет,

то "кредитовать_счет";

если запрос,

то "выдать_запрос";

во всех случаях: квитанция должна содержать номер ATM, дату, время,

номер счета, вид проводки, сумму проводки (если она есть), новый баланс счета

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

В банковской сети можно ввести следующие ограничения: 

"счет не может иметь отрицательного баланса"; 

"отрицательный баланс кредитуемого счета не может быть больше лимита кредитования для этого счета". 

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

Оптимизационные критерии для банковской сети: 

минимизировать количество физических пересылок между различными узлами сети; 

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

Операции вводятся на различных стадиях разработки модели проектируемой системы (см. выше): 

при разработке объектной модели; 

при определении событий; 

при определении действий и активностей; 

при определении функций. 

На этапе разработки модели проектируемой системы все введенные операции вводятся в ее объектную модель. 

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



2. Конструирование системы

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

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

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



2.1. Разработка архитектуры системы

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

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

На этапе конструирования системы ее разработчик должен принять следующие решения: 

определить разбиение системы на модули;

выявить асинхронный параллелизм в системе;

определить состав вычислительного комплекса, на котором будет работать система;

распределить компоненты системы по процессорам вычислительного комплекса и независимым задачам;

организовать управление хранилищами данных;

организовать управление глобальными ресурсами;

выбрать принципы реализации управления программным обеспечением;

организовать управление пограничными ситуациями. 



2.1.1. Разбиение системы на модули

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

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

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

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

Подсистемы (и реализующие их модули) могут образовывать в системе уровни, либо разделы. 

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

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

Система с уровневой архитектурой при переносе на другую платформу требует переписывания только одного (самого нижнего) уровня. Пример системы с уровневой архитектурой представлен на рисунке 2.1. 





Рисунок 2.1 - Пример системы с уровневой архитектурой



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

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





Рисунок 2.2 - Топология звезды



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



2.1.2. Выявление асинхронного параллелизма

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

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

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

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



2.1.3. Распределение модулей и подсистем по процессорам и задачам

Каждый асинхронный (независимый) объект (модуль или подсистема) должен быть приписан к одному из устройств аппаратуры: универсальному процессору или специализированному функциональному устройству. Разработчик системы должен: 

оценить требуемую производительность и требуемые ресурсы;

выбрать способ реализации подсистем (аппаратный или программный);

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

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

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

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

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

При распределении модулей и подсистем по процессорам следует иметь в виду следующее: 

некоторые задачи нужно выполнять на определенных устройствах; например, обработку банковской карточки следует выполнять на БМ;

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

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



2.1.4. Управление хранилищами данных

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

В базах данных обычно размещают данные, удовлетворяющие одному из следующих условий: 

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

данные, которые могут эффективно управляться командами СУБД;

данные, которые должны переноситься на многие платформы;

данные, для которых требуется доступ со стороны нескольких прикладных программ.

В файлах удобно размещать данные, удовлетворяющие одному из следующих условий: 

данные, которых много, но которые плохо поддаются структуризации;

данные с низкой информационной плотностью (например, дампы);

"сырые" данные, подготавливаемые для баз данных;

"летучие" данные, которые хранятся короткое время, а потом удаляются. 



2.1.5. Реализация управления программным обеспечением

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

последовательное управление процедурами,

последовательное управление событиями,

параллельное асинхронное управление.

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

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

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



2.1.6. Пограничные ситуации

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

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

Терминация состоит в освобождении всех внешних ресурсов, занятых задачами системы. 

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



2.1.7. Архитектур прикладных систем

Существует несколько типов архитектур, обычно используемых в существующих системах. Каждая из них хорошо подходит к определенному типу систем. Проектируя систему одного из нижеперечисленных типов, имеет смысл использовать соответствующую архитектуру. Мы рассмотрим следующие типы систем: 

системы пакетной обработки - обработка данных производится один раз для каждого набора входных данных;

системы непрерывной обработки - обработка данных производится непрерывно над сменяющимися входными данными;

системы с интерактивным интерфейсом - системы, управляемые внешними воздействиями;

системы динамического моделирования - системы, моделирующие поведение объектов внешнего мира;

системы реального времени - системы, в которых преобладают строгие временные ограничения;

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

типичной системой управления транзакциями является СУБД.

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

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

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

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



Рисунок 2.3 - Система непрерывной обработки: машинная графика



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

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

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

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

При разработке системы с интерактивным интерфейсом необходимо выполнить следующие шаги: 

Выделяем объекты, формирующие интерфейс.

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

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

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

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

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

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

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





Рисунок 2.4 - Система с интерактивным интерфейсом: БМ



Моделирование управляется объектами, отслеживающими временные циклы последовательностей событий.

Разработка системы реального времени аналогична разработке системы с интерактивным интерфейсом. 

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

Отображаем объектную модель на базу данных.

Определяем асинхронно работающие устройства и ресурсы с асинхронным доступом; в случае необходимости определяем новые классы.

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

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

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

Архитектура системы управления банковской сетью показана на рисунке 2.5. Система имеет три основных подсистемы: подсистему обслуживания БМ, подсистему консорциум и подсистему банк. Система имеет топологию звезды, в центре которой - подсистема консорциум, а на лучах - подсистемы БМ и банк (ясно, что в состав системы входит одна подсистема консорциум и по несколько подсистем БМ и банк). 



Рисунок 2.5 - Архитектура системы управления банковской сетью



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

Асинхронная параллельность возникает в связи с необходимостью параллельного обслуживания нескольких независимо работающих БМ и кассовых терминалов. Каждый терминал может одновременно обслуживать только одну проводку (транзакцию), но каждая проводка связана также с центральным компьютером консорциума и компьютером одного из банков, которые должны одновременно обслуживать несколько проводок. Как видно из рисунка 2.5 каждая проводка распределена по трем устройствам, управляющее ее выполнением программное обеспечение состоит из трех частей; каждая из этих частей может быть реализована в виде отдельного класса. 



2.2. Разработка объектов

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

Разработка объектов предполагает выполнение следующих шагов: 

Рассматривая совместно три модели, получаем операции над классами.

Разрабатываем алгоритмы, реализующие полученные операции.

Оптимизируем пути доступа к данным.

Реализуем управление взаимодействиями с внешними объектами.

Уточняем структуру классов, чтобы повысить степень наследования.

Разрабатываем зависимости.

Определяем представления объектов. 



2.2.1. Совместное рассмотрение трех моделей

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

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

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



2.2.2. Разработка алгоритмов, реализующих полученные операции

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

вычислительная сложность алгоритма: для алгоритмов, применяемых к достаточно большим массивам данных, важно, чтобы оценка их вычислительной сложности была разумной; например, вряд ли имеет смысл избегать косвенности в ссылках, особенно когда введение косвенности существенно упрощает понимание программы; в то же время замена пузырьковой сортировки с оценкой сложности n2 на алгоритм сортировки с оценкой n*log n всегда резко ускоряет вычисления;

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

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

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

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

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

При распределении операций по классам руководствуются следующими соображениями: 

если операция выполняется только над одним объектом, то она определяется в классе, экземпляром которого является этот объект;

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

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

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



2.2.3. Оптимизация разработки

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

добавляются избыточные зависимости, чтобы минимизировать потери, связанные с доступом к данным, и максимизировать удобство работы с ними;

изменяется порядок вычислений для достижения большей эффективности;

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

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



Рисунок. 2.6 - Использование производных атрибутов для исключения повторных вычислений





Рисунок 2.7 - Использование производной зависимости



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

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

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

периодическое перевычисление всех производных атрибутов (в момент изменения базового значения производные атрибуты перевычисляются);

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



2.2.4. Реализация управления

Реализация управления связана с реализацией динамической модели объектов системы. Известны три подхода к реализации динамической модели: 

процедурное управление: состоянию соответствует определенный фрагмент программы;

управление через события: явная реализация конечного автомата;

использование параллельных независимых задач.

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



Рисунок 2.8 - Псевдокод, соответствующий динамической модели БМ



2.2.5. Уточнение наследования классов

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

Перестроить классы и операции.

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

Использовать делегирование операций, когда наследование семантически некорректно.

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

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

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

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

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

Использование делегирования операций можно пояснить на следующем примере (рисунок 2.9). Класс стек близок классу список, причем операциям стека push и pop соответствуют очевидные частные случаи операций списка add и remove. Если реализовать класс стек как подкласс класса список, то придется применять вместо операций push и pop более общие операции add и remove, следя за их параметрами, чтобы избежать записи или чтения из середины стека; это неудобно и чревато ошибками. Гораздо лучше объявить класс список телом класса стек (делегирование), обращаясь к операциям списка через операции стека. При этом, не меняя класса список, мы заменяем его интерфейс интерфейсом класса стек. 





Рисунок 2.9 - Реализация стека с использованием наследования (а) и делегирования (б)



2.2.6. Разработка зависимостей

Зависимости - это "клей" объектной модели: именно они позволяют рассматривать модель как нечто целое, а не просто как множество классов. 

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





Рисунок 2.10 - Реализация односторонней зависимости



На рисунке 2.11 показан способ реализации двусторонней зависимости с помощью указателей.  





Рисунок 2.11 - Реализация двусторонней зависимости



На рисунке 2.12 показан способ реализации зависимости с помощью таблицы (как в реляционных базах данных).  



Рис. 2.12. Реализация зависимости с помощью таблицы



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



3. Реализация объектно-ориентированного проекта

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

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

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

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

Данный фрагмент программы реализует два вида счетов - расчетный счет (класс CheckingAccount) и депозитный счет (класс DepositAccount) - с помощью наследования из базового класса Account.

Класс Account - это абстрактный класс с чисто виртуальным методом GetAccountTypc. Кроме того, он задает общие для всех порожденных из него классов методы- Deposit, Withdraw и Balance. Вызывая эти методы, программы, работающие с базовым классом, будут использовать ограниченный полиморфизм.

Атрибут amount - остаток на счету - помещен в защищенную часть класса для того, чтобы порожденные классы могли с ним работать. Атрибут accountNumber - номер счета - помещен во внутреннюю часть класса, поскольку базовый класс полностью контролирует создание уникальных номеров счетов.



//

// Класс Account - базовый класс для всех типов счетов

//

class Account

{

// внешняя часть класса, его интерфейс 

public:

// перечисление всех возможных типов счетов

enum AccountType ( CHECKING, DEPOSIT );

Account() ( amount = 0; );   		 // Создание пустого счета 

Account(long _accountNumber);	 // Создание объекта для

// имеющегося счета 

virtual ~Account() ;

// Хотя класс Account абстрактный, он проводит

// стандартные реализации методов "положить на счет"

// (Deposit), "снять со счета" (Withdraw) и

// "остаток на счете" (Balance), хотя они могут быть

// переопределены в порожденных классах

virtual void Deposit(float _amount);		//Положить на счет

virtual bool Withdraw(float _ainount);	//Снять со счета

virtual float Balance(void) const;	//Остаток на счете

// Метод GetAccountType возвращает тип конкретного счета

// и определен только в порожденных классах

virtual AccountType GetAccountType(void) consfc = 0;

// Узнать номер счета

long GetAccountNumber(void) const

{ return accountNumber; } ;

// Защищенная часть класса доступна порожденным классам 

protected:

float amount;             // Атрибут - сумма на счете 

// Внутренняя часть класса 

private:

long accountNumber;    	// Атрибут - номер счета

};



Класс DatabaseObject - абстрактный класс, который задает интерфейс для сохранения и восстановления объектов в базе данных. Порожденные из него классы обязаны определить два метода: Save - для сохранения самого себя в базе данных, и Restore - для восстановления состояния из базы данных. В данном классе показано, что в абстрактном классе могут задаваться конкретные методы (MarkModifled, IsModifled, GetDatabaseConnection). Если первые два метода относятся к интерфейсу класса, то третий - это защищенный метод, необходимый для реализации методов Save и Restore в порожденных классах. (Мы исходим из предположения, что операции с базой данных требуют установления соединения с базой данных через объект типа DBConnection, который и возвращает метод GetDatabaseConnection.)

//

// Базовый класс для всех'объектов,

// которые могут храниться в базе данных

//

class DatabaseObject

{

public:

DatabaseObject () :niodifiedFlag( false) {}

virtual ~DatabaseObject() ;

virtual boot Save(void) = 0;

virtual boot Restore(void) = 0;

// Два дополнительных метода устанавливают или проверяют 

// признак того, что объект был модифицирован и должен 

// быть сохранен в базе данных 

void MarkModified(void) ;

boot IsModified(void) const;

protected:

DBConnection* GetDatabaseConnection(void);

private:

boot modifiedFlag;

};



Два следующих класса: CheckingAccount и DepositAccount - это конкретные классы, реализующие два типа счетов - расчетный счет и депозит. Они используют множественное наследование. В качестве базовых классов выступают классы Account и DatabaseObject. Класс Account задает интерфейс и стандартную реализацию свойств счета, а класс DatabaseObject - необходимый интерфейс для хранения объектов в базе данных.



//

// Класс Расчетный счет - конкретный счет, который

// может храниться в базе данных

//

class CheckingAccount : public Account, DatabaseObject

{ 

public:

CheckingAccount() {} ;

CheckingAccount(long _accountNumber) •;

Account (_accountNuinber) {} ;

// При конструировании нового объекта данного 

// класса мы вначале конструируем его 

// базовую часть

virtual ~CheckingAccount ();

// Класс переопределяет метод снятия со счета, потому 

// что имеется требование минимального остатка на счете,

// оставляя неизменными методы "положить на счет" 

//и "проверить остаток" 

virtual boot Withdraw(float _amount);

// Метод GetAccountType определен и возвращает тип 

// счета - расчетный счет

virtual AccountType GetAccountType(void) const 

( return CHECKING;) ;

// Поскольку объекты данного класса можно хранить 

//в базе данных - класс выведен из DatabaseObject, 

//в нем определяются методы Save и Restore для 

// сохранения и восстановления из базы данных 



virtual boot Save(void) ;

virtual boot Restore(void) ;

private:

// Класс определяет один дополнительный атрибут 

//минимальный остаток на счете 

float minBalance;

};



//

// Класс счет-депозит, аналогичный предыдущему

// расчетному счету

//

class DepositAccount : public Account, DatabaseObject

{

DepositAccount() {}; ,

DepositAccount (long _accountNurnber) :

Account (_accountNuinber) {};

virtual ~DespositAccount() ;

// Класс переопределяет метод снятия со счета и метод

// "положить на счет", потому что имеется ограничение,

//в какие сроки можно их производить,

// метод "проверить остаток" также переопределен,

// поскольку на сумму начисляется процент

virtual void Deposit(float _amount);

virtual boot Withdraw(float amount);

virtual float Balance(void) const;

// Метод GetAccountType определен и возвращает тип 

// счета - депозит

virtual AccountType GetAccountType(void) const 

( return DEPOSIT;);

// Поскольку объекты данного класса можно хранить 

//в базе данных - класс выведен из DatabaseObject, 

// в нем определяются методы Save и Restore для 

// сохранения и восстановления из базы данных 

virtual boot Save(void) ;

virtual boot Restore(void) ;

// Два дополнительных метода определяют, прошел ли срок

// депозита и каков процент на этот вклад

bool IsMature(void) const;

float GetInterestRate(void) const;

private :

// Два дополнительных атрибута хранят срок

// депозита и процент на этот вклад

Date maturityDate;

float interestRate;

};



Класс AccountFactory - это пример использования понятия фабрики объектов в языке Си++. Фабрика объектов - это класс, результатом вызова метода которого являются новые объекты другого класса. Хотя непосредственно новые объекты создаются с помощью вызова оператора new, фабрика объектов позволяет инкапсулировать процесс создания объектов разных конкретных классов (CheckingAccount, DepositAccount) в одном статическом методе CreateAccount.

Кроме того, этот класс иллюстрирует статические (static) методы класса. Эти методы не требуют объекта для своего выполнения, Они выполняются от имени класса. Таким образом, класс AccountFactory эмулирует метакласс, поскольку «настоящие» метаклассы отсутствуют в Си++.



//

// Класс AccountFactory используется для создания 

// новых счетов

// 

class AccountFactory

{

public:

// метод CreateAccount создает новый счет определенного

// типа с начальным вкладом _initialAmount, процентом

//по вкладу _interestRate и сроком _maturityDate.

// Последние два аргумента необязательны и не

// задаются для расчетных счетов

static Account* CreateAccount(Account::AccountType _t, 

float _initialAmount, 

float _interestRate = 0, 

Date _maturityDate e «»);

// Глобальный метод GetNewAccountNumber

// генерирует новые, уникальные номера счетов

static long GetNewAccountNumber(void);

}:




Литература



		Иванова Г.С. Технология программирования: Учебник для вузов. –2-е изд., степеотип. –М.:Изд-во МГТУ им Н.Э.Баумана, 2003. 

		Корпоративные системы на основе CORBA. Пер. с англ. : Уч.пос. –М.:Издательский дом «Вильямс», 2000.

		Ларман К. Применение UML и шаблонов проектирования. М.:Издательский дом «Вильямс», 2001.

		Мацяшек Л.А. Анализ требований и проектирование систем. Разработка информационных систем с использованием UML. Пер. с англ. –М.: Издательский дом «Вильямс», 2002





2