Главная » UML » Множественная и динамическая классификация UML

0

 

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

При однозначной классификации (single classification) любой объект принадлежит единственному типу, -который может быть унаследован от супертипов. Во множественной классификации (multiple classification) объект может быть описан несколькими типами, которые не обязательно должны быть связаны наследованием.

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

В качестве примера рассмотрим тип Person (Личность), подтипами которого являются Male (Мужчина) или Female (Женщина), Doctor (Доктор) или Nurse (Медсестра), Patient (Пациент) или вообще никто (рис. 5.11). Множественная классификация позволяет некоторому

 

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

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

По определению множества обобщения не пересекаются: каждый экземпляр супертипа может быть экземпляром только одного подтипа из данного множества. Если вы соединяете линии обобщений с одной стрелкой, то они должны входить в одно и то же множество обобщения, как показано на рис. 5.11. Альтернативный способ – изобразить несколько стрелок с одинаковой текстовой меткой.

В качестве иллюстрации отметим на диаграмме следующие допустимые комбинации подтипов: (Female, Patient, Nurse); (Male, Physiotherapist (Физиотерапевт)); (Female, Patient) и (Female, Doctor, Surgeon (Хирург)). Комбинация (Patient, Doctor, Nurse) является недопустимой, поскольку она содержит два типа из множества обобщения role (роль).

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

 

 

 

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

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

Класс-ассоциация

Классы-ассоциации (association classes) позволяют дополнительно определять для ассоциаций атрибуты, операции и другие свойства, как показано на рис. 5.12. Из данной диаграммы видно, что Person (Личность) может принимать участие в нескольких совещаниях (Meeting). При этом необходимо каким-то образом хранить информацию о том, насколько внимательной была данная личность; это можно сделать, добавив к ассоциации атрибут attentiveness (внимательность).

 

 

На рис. 5.13 показан другой способ представления данной информации: образование самостоятельного класса Attendance (Присутствие). Обратите внимание, как при этом изменили свои значения кратности.

 

 

 

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

Посмотрим на две диаграммы, изображенные на рис. 5.14. Форма этих диаграмм практически одинакова. Хотя можно себе представить компанию (Company), играющую различные роли (Role) в одном и том же контракте (Contract), но трудно вообразить личность (Person), имеющую различные уровни компетенции в одном и том же навыке (Skill); действительно, скорее всего, это можно считать ошибкой.

В языке UML допустим только последний вариант. Может существовать только один уровень компетенции для каждой комбинации личности и навыка. Верхняя диаграмма на рис. 5.14 не допускает участия компании более чем в одной роли в одном и том же контракте. Если без этого не обойтись, надо превратить Role в полный класс, как это сделано на рис. 5.13.

 

 

 

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

 

class Person

List getAttendances()

List getMeetings()

 

Таким образом, клиенты объекта Person могут обнаружить сотрудников на совещании; если им требуются детали, то они могут получить собственно часы работы (Attendance). Если вы так делаете, не забудьте об ограничении, при котором для любой пары объектов Person (Личность) и Meeting (Совещание) может существовать только один объект Attendance (Присутствие).

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

 

 

Если я встречаю временную информацию такого типа, то использую для ассоциации ключевое слово «temporal» (временной) (рис. 5.16). Модель означает, что некоторое время личность может работать только в одной компании. Однако по прошествии времени личность сможет работать в нескольких компаниях. Это предполагает интерфейс, описываемый следующими строками:

class Person …

Company getEmployer();     // определение текущего работодателя

Company getEmployer(Date);       // определение работодателя на указанный момент

void changeEinployer(Company newEmployer.Date changeDate);

void leaveEmployer (Date changeDate);

Ключевое слово «temporal» не входит в состав языка UML, но я упомянул его здесь по двум причинам. Во-первых, это понятие часто оказывалось полезным для меня как проектировщика. Во-вторых, это демонстрирует, как можно применять ключевые слова для расширения языка UML. Дополнительную информацию по данному вопросу можно найти на http://maHinfowler.com/ap2/timeNarrative.html

 

 

 

Шаблон класса (параметризованный класс)

Некоторые языки, в особенности C++, включают в себя понятие параметризованного класса (parameterized class) или шаблона (template). (Шаблоны могут быть включены в языки Java и С# в ближайшем будущем.)

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

class Set <T> {

void insert (T newElement);

void remove (Т anElement);

 

После этого можно использовать данное общее определение для задания более конкретных классов-множеств:

Set <Еmрlоуее> employeeSet;

Для объявления класса-шаблона в языке UML используется нотация, показанная на рис. 5.17. Прямоугольник с буквой «Т» на диаграмме служит для указания параметра типа. (Можно указать более одного параметра.)

 

 

Применение параметризованного класса, такого как Set<Employee>, называется образованием производных (derivation). Образование производных можно изобразить двумя способами. Первый способ отражает синтаксис языка C++ (рис. 5.18). Выражение образования производных описывается в угловых скобках в виде <parameter-name: :parameter-valuex Если указывается только один параметр, то обычно имя параметра опускают. Альтернативная нотация (рис. 5.19) усиливает связь с шаблоном и допускает переименование связанного элемента.

 

 

Ключевое слово «bind» (связать) является стереотипом отношения уточнения. Это отношение означает, что класс EmployeeSet (Множество служащих) будет согласован с интерфейсом класса Set. Можете считать EmployeeSet подтипом типа Set. Это соответствует другому способу реализации типизированных коллекций, который заключается в объявлении всех соответствующих подтипов.

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

 

Источник: Фаулер М.UML. Основы, 3-е издание. – Пер. с англ. – СПб: Символ-Плюс, 2006. – 192 с.,ил.

По теме:

  • Комментарии