Моделирование на UML. Ф.Новиков, Д.Иванов.
<< 2.3. Реализация вариантов использования 3.2. Сущности на диаграмме классов >>

3. Моделирование структуры

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

3.1. Принципы моделирования структуры

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

3.1.1. Дескрипторы

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

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

function MaxFib : integer;
var f1, f2 : integer;
begin
    f1:=1; f2:=1;
    while maxint – f1 > f2 do begin
        f2 := f1 + f2;
        f1 := f2 – f1
    end;
    MaxFib := f2
end;

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

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

Синтаксическая диаграмма для понятия «программа»

Рис. Синтаксическая диаграмма для понятия «программа»

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

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

В UML этот принцип формализован в виде понятия дескриптора.

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

Дескриптор имеет две стороны: это само описание множества (intent) и множество значений, описываемых дескриптором (extent). Антонимом для дескриптора является понятие литерала (literal). Литерал описывает сам себя. Например, тип данных integer является дескриптором: он описывает множество целых чисел, потенциально бесконечное (или конечное, но достаточно большое, если речь идет о машинной арифметике). Изображение числа 1 описывает само число "один" и более ничего ‒ это литерал. Почти все элементы моделей UML являются дескрипторами ‒ именно поэтому средствами UML удается создавать представительные модели достаточно сложных систем. Рассмотренные в предыдущей главе варианты использования и действующие лица ‒ дескрипторы, рассматриваемые в этой главе классы, ассоциации, компоненты, узлы ‒ также дескрипторы. Комментарий же является литералом ‒ он описывает сам себя. Пакет также является литералом.

3.1.2. Назначение структурного моделирования

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

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

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

Структура связей между объектами во время выполнения программы. В парадигме объектно-ориентированного программирования процесс выполнения программы состоит в том, что программные объекты взаимодействуют друг с другом, обмениваясь сообщениями. Наиболее распространенным типом сообщения является вызов метода объекта одного класса из метода объекта другого класса. Для того чтобы вызвать метод объекта, нужно иметь доступ к этому объекту. На уровне программной реализации этот доступ может быть обеспечен самыми разнообразными механизмами. Например, объект, вызывающий метод, может хранить указатель (ссылку) на объект, содержащий вызываемый метод. Еще вариант: ссылка на объект с вызываемым методом может быть передана в качестве аргумента объекту, который этот метод вызовет. Возможно, используется какой-либо механизм удаленного вызова процедур, обеспечивающий доступ к объектам (например, такой, как CORBA) по их идентификаторам. Если атрибуты объектов представлены записями в таблице базы данных, а методы (нередкий вариант реализации) ‒ хранимыми процедурами системы управления базами данных (СУБД), то идентификация объектов осуществляется по первичному ключу таблицы. Как бы то ни было, во всех случаях имеет место следующая ситуация: один объект "знает" другие объекты и, значит, может вызвать открытые методы, использовать и изменять значения открытых атрибутов и т.д. В этом случае, мы говорим, что объекты связаны, т.е. между ними есть связь. Для моделирования структуры связей в UML используются отношения ассоциации на диаграмме классов.

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

  • persistent ‒ экземпляры классификатора, ассоциации или значения атрибута, соответственно, должны быть хранимыми;
  • transient ‒ противоположно предыдущему — сохранять экземпляры не требуется (значение по умолчанию).

В настоящее время самым распространенным способом хранения объектов является использование СУБД. При этом хранимому классу соответствует таблица базы данных, а хранимый объект (точнее говоря, набор значений хранимых атрибутов) представляется записью в таблице. Вопрос структуры хранения данных является первостепенным для приложений баз данных. К счастью, известны надежные методы решения этого вопроса ‒ схемы баз данных, диаграммы "сущность–связь". Эти же методы (с точностью до обозначений) применяются и в UML в форме ассоциаций с указанием кратности полюсов.

Структура программного кода. Не секрет, что программы существенно отличаются по величине ‒ бывают программы большие и маленькие. Удивительным является то, насколько велики эти различия: от сотен строк кода (и менее) до сотен миллионов строк (и более). Столь большие количественные различия не могут не проявляться и на качественном уровне. Действительно, для маленьких программ структура кода практически не имеет значения, для больших ‒ наоборот, имеет едва ли не решающее значение. Поскольку UML не является языком программирования, модель не определяет структуру кода непосредственно, однако косвенным образом структура модели существенно влияет на структуру кода. Большинство инструментов поддерживает полуавтоматическую генерацию кода для одного или нескольких, чаще объектно-ориентированных, языков программирования. В большинстве случаев классы модели транслируются в классы (или эквивалентные им конструкции) целевого языка. Кроме того, многие инструменты учитывают структуру пакетов в модели и транслируют ее в соответствующие "надклассовые" структуры целевой системы программирования. Таким образом, если задействовано средство автоматической генерации кода, то структура классов и пакетов в модели фактически полностью моделирует структуру кода приложения.

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

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

Структура артефактов в проекте. Только самые простые приложения состоят из одного артефакта ‒ исполнимого кода программы. Большинство реальных приложений насчитывает в своем составе десятки, сотни и тысячи различных компонентов: исполнимых двоичных файлов, файлов ресурсов, файлов исходного кода, различных сопровождающих документов, справочных файлов, файлов с данными и т.д. Для большого приложения важно не только иметь точный и полный список всех артефактов, но и указать, какие именно из них входят в конкретный экземпляр системы. Дело в том, что для больших приложений в проекте сосуществуют разные версии одного и того же артефакта. Это исчерпывающим образом моделируется диаграммами компонентов и размещения UML, где предусмотрены стандартные стереотипы для описания артефактов разных типов.

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

3.1.3. Классификаторы

Важнейшим типом дескрипторов являются классификаторы.

Классификатор (classifier) ‒ это дескриптор множества однотипных объектов.

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

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

Классификаторы, которые рассмотрены в этой главе, приведены ниже:

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

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

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

Если некоторый объект непосредственно порожден с помощью конструктора классификатора А, то этот объект называется прямым экземпляром (direct instance) классификатора А 1.

Если классификатор А является обобщением классификатора В или, что то же самое, классификатор В является специализацией классификатора А, то все экземпляры классификатора В являются косвенными экземплярами классификатора А 2.

Данное свойство является транзитивным: если классификатор А является обобщением классификатора В, а классификатор В является обобщением классификатора С, то все экземпляры классификатора С также являются косвенными экземплярами А 3.

Название рисунка

Рис. Прямые и косвенные экземпляры классификатора A

В-третьих, классификатор может быть абстрактным или конкретным.

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

Конкретный (concrete) классификатор может иметь прямые экземпляры и в этом случае его имя записывается прямым шрифтом.

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

В-четвертых, классификатор (как и другие элементы модели) имеет видимость.

Видимость (visibility) определяет, может ли составляющая одного классификатора (в том числе имя) использоваться в другом классификаторе.

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

  • открытый (обозначается знаком + или ключевым словом public);
  • защищенный (обозначается знаком # или ключевым словом protected);
  • закрытый (обозначается знаком или ключевым словом private).
  • пакетный (обозначается знаком ~ или ключевым словом package).

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

Например, защищенный атрибут класса виден в содержащем его классе и во всех подклассах. Закрытый элемент модели виден только в элементе, которому он принадлежит. Например, закрытый атрибут класса виден только в этом классе.

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

Закрытый элемент модели виден только в элементе, которому он принадлежит. Например, закрытый атрибут класса виден только в этом классе.

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

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

В-пятых, все составляющие классификатора имеют область действия.

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

Область действия имеет два возможных значения:

  • экземпляр (instance) — никак специально не обозначается, поскольку подразумевается по умолчанию;
  • классификатор (classifier) — описание составляющей классификатора подчеркивается.

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

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

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

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

Нижняя граница .. ВЕРХНЯЯ ГРАНИЦА

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

Табл. Выражения кратности

Выражение кратности Множество может иметь
0..* или * Произвольное число элементов
1..* Один или более элементов
0..1 Не более одного элемента
1..10 От одного до десяти элементов
1..3, 5, 7..10 Один, два, три, пять, семь, восемь, девять или десять элементов
5..3 Некорректная кратность. Нижняя граница больше верхней
-1..3 Некорректная кратность. Отрицательные числа недопустимы

Обычно на практике используются следующие варианты кратности классификаторов.

Классификатор не имеет экземпляров (кратность 0) ‒ такой классификатор называется службой (utility). Все составляющие службы имеют областью действия классификатор. Хранение информации, обрабатываемой службой, обеспечивают объекты, использующие службу. Типичный пример ‒ набор процедур общего пользования, скажем, библиотека математических функций. Службы используются в приложениях достаточно часто, поэтому есть даже стандартный стереотип «utility», определяющий классификатор как службу (см. параграф 3.2.1).

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

Классификатор имеет фиксированное число экземпляров (например, кратность 8). Такой вариант не часто, но встречается. Например, моделирование портов в концентраторе.

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

И, наконец, в-седьмых, классификаторы (и только они!) могут участвовать в отношении обобщения (см. параграф 3.3.2)

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

Часть метамодели классификатора

Рис. Часть метамодели классификатора

3.1.4. Идентификация классов

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

  • словарь предметной области;
  • реализация вариантов использования (см. раздел 2.3);
  • образцы проектирования (см. параграф 3.5.3).

Словарь предметной области (domain dictionary) ‒ это набор основных понятий (сущностей) данной предметной области.

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

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

  • прием;
  • перевод;
  • увольнение;
  • сотрудник;
  • создание;
  • ликвидация;
  • подразделение;
  • вакансия;
  • сокращение;
  • должность.

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

  • сотрудник,
  • подразделение;
  • вакансия;
  • должность.

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

  • Сотрудник (Person).
  • Подразделение (Department).
  • Должность (Position).

Рассмотрим теперь, как выявляются классы в процессе реализации вариантов использования (см. раздел 2.3). Если при реализации вариантов использования применяются диаграммы взаимодействия (параграф 2.3.4), то в этом процессе в качестве побочного эффекта выделяются некоторые классы непосредственно, поскольку на диаграммах коммуникации и последовательности основными сущностями являются объекты, которые по необходимости нужно отнести к определенным классам. Использование диаграмм деятельности (параграф 2.3.3) также может подсказать, какие классы нужно определить в системе, особенно если на диаграмме деятельности наряду с потоком управления (control flow) присутствует поток данных (data flow). Однако, если сценарии вариантов использования описываются на естественном языке или псевдокоде (параграф 2.3.1 и параграф 2.3.2), то выделить классы значительно труднее. Фактически, если варианты использования реализуются на псевдокоде или диаграммами деятельности без всякой связи с объектами, то выявление объектной структуры системы просто откладывается "на потом". Иногда это может быть вполне оправдано — например, архитектор, моделирующий систему, прежде чем начать проектирование основной структуры классов, хочет более глубоко вникнуть в логику бизнес-процессов незнакомой ему предметной области.

Обсудим это на примере информационной системы отдела кадров. Реализация вариантов использования Self Fire и Adm Fire не дает практически никакой информации для выделения классов.

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

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

Два класса ‒ Person и Position ‒ те же, что нам подсказал анализ словаря предметной области. Очевидно, что если одни и те же выводы получены разными способами, доверие к ним возрастает. Полезный класс Exceptions Handler, однако, вряд ли мог появиться из словаря: описывая предметную область, люди склонны закрывать глаза на возможные ошибки, исключительные ситуации и прочие неприятности.

Особого обсуждения заслуживает появление класса Hire Form, но его мы пока оставим в стороне (см. раздел 3.5.3).

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


3.2. Сущности на диаграмме классов >>
Моделирование на UML. Ф.Новиков, Д.Иванов.