Главная страница

UML2 и унифицированный процесс. Джим арлоуайла нейштадтпрактический объектно ориентированныйанализ и проектированиеu


Скачать 6.08 Mb.
НазваниеДжим арлоуайла нейштадтпрактический объектно ориентированныйанализ и проектированиеu
АнкорUML2 и унифицированный процесс.pdf
Дата08.04.2018
Размер6.08 Mb.
Формат файлаpdf
Имя файлаUML2 и унифицированный процесс.pdf
ТипДокументы
#17801
страница57 из 62
1   ...   54   55   56   57   58   59   60   61   62
25.10.7. derive:
OCL может использоваться для определения значений производных атрибутов.
Значения производных атрибутов определяются с помощью derive.
Наш пример с банковским счетом можно реорганизовать и выразить переменную баланса и переменную превышения кредита с помощью производных атрибутов (рис. 25.14).
Правила вывода этих производных атрибутов можно описать следую щим образом:
context CheckingAccount::availableBalance : Real derive:
можно снимать сумму, не превышающую ограничения по превышению кредита balance + overDraftLimit context CheckingAccount::availableOverdraft : Real derive:
if balance >= 0 then возможность превышения кредита доступна полностью overdraftLimit

25.11. OCL на диаграммах других типов
567
else возможность превышения кредита использована частично overdraftLimit + balance endif
Это упрощает определение операций
CheckingAccount::getAvailableBal ance() и CheckingAccount::getAvailableOverdraft():
context CheckingAccount::getAvailableBalance() : Real body:
availableBalance context CheckingAccount::getAvailableOverdraft() : Real body:
availableOverdraft
25.11. OCL на диаграммах других типов
До сих пор мы рассматривали применение OCL только на диаграммах классов. Однако OCL может также использоваться на диаграммах дру гих типов:

на диаграммах взаимодействий (глава 12);

на диаграммах деятельности (главы 14 и 15);

на диаграммах состояний (конечные автоматы) (главы 21 и 22).
В следующих разделах рассмотрим применение OCL на диаграммах этих типов.
BankAccount balance : Real accountNumber : String deposit( amount : Real ):Real withdraw( amount : Real )
getBalance() : Real getOwner() : Person getOperators() : Person[]
CheckingAccount overdraftLimit : Real
/availableBalance : Real
/availableOverdraft : Real withdraw( amount : Real )
getAvailableBalance() : Real getAvailableOverdraft() : Real
DepositAccount withdraw( amount : Real )
Person name : String id : String address : String getName() : String getId() : String getAddress() : String owner operator
1..*
*
*
1
ownedAccounts operatedAccounts производные атрибуты
Рис. 25.14. Производные атрибуты

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

определить сторожевое условие;

определить селектор линии жизни (раздел 12.6);

определить параметры сообщения.
Рассмотрим пример использования OCL на диаграммах последова тельностей. На рис. 25.15 изображена диаграмма классов простой сис темы электронной почты.
Класс
EmailAddress (электронный адрес) представляет адрес электрон ной почты. Например, адрес электронной почты jim@umlandtheuni
fiedprocess.com
был бы представлен как объект класса
EmailAddress, как показано на рис. 25.16. В данном случае операция
EmailAddress:get blacklist
0..*
whiteList
0..*
EmailAddress
getName() : String getDomain() : String getAddress() : String

address : String replyTo cc bcc fromAddress toAddresses
0..1 0..*
0..*
1 1..*
Legitimate
Unclassified
<>
MessageType
messageType
1 1
MailSystem
MailSystem
classifyMessage( m : Message )

reviewBox inBox
0..*
0..*
1 1
subject : String content : String setType( type : MessageType )

1 1
1 1
1 1
1
Рис. 25.15. Диаграмма классов системы электронной почты

25.11. OCL на диаграммах других типов
569
Name() возвращает "Jim", EmailAddress::getDomain() возвращает "umlandthe unifiedprocess.com" и EmailAddress::getAddress() возвращает "jim@umlandthe unifiedprocess.com". Объекты EmailAddress эквивалентны, если их атрибу ты address (адрес) имеют одинаковое значение.
Система для обработки пришедшей почты пользуется политикой бе лый/черный список:

Все почтовые сообщения, адрес отправителя (
fromAddress) которых входит в черный список (
blackList), удаляются.

Все почтовые сообщения, fromAddress которых входит в белый спи сок (
whiteList), помещаются в ящик входящей почты (inBox).

Все остальные почтовые сообщения помещаются в ящик для про смотра (
reviewBox).

Состояние пришедшего сообщения (
Message) меняется соответствен но его типу: спам (удаляется),
Legitimate (допустимый) или Unclassi fied (неклассифицированный).
На рис. 25.17 показана диаграмма последовательностей для операции
MailSystem::classifyMessage( m : Message ). Диаграмма деятельностей для этой операции представлена в следующем разделе на рис. 25.18, и вы должны заметить, как эти диаграммы соответствуют друг другу. Диа грамма последовательностей определяет, какие классы и операции реализуют поведение, описанное диаграммой деятельностей.
MailSystem (система электронной почты) – контекст выражения. OCL
использовался для определения условий в комбинированном фрагмен те alt.
С помощью OCL также было задано состояние объектов на диаграмме
(хотя это обычное применение OCL, поскольку OCL и UML имеют оди наковый синтаксис для описания состояний).
25.11.2. OCL на диаграммах деятельности
Диаграммы деятельности можно создавать для описания поведения любого элемента UML моделирования. На диаграммах деятельностей
OCL используется для определения:

узлов вызова действия;

сторожевых условий переходов;

объектных узлов;

состояния объекта.
jimsAddress:EmailAddress address = "jim@umlandtheunifiedprocess.com"
Рис. 25.16. Адрес электронной почты jim@umlandtheunifiedprocess.com
представлен как объект класса
EmailAddress

570
Глава 25. Введение в OCL
Например, на рис. 25.18 показана очень простая диаграмма деятель ности для описания поведения
ClassifyMailMessage (классифицировать почтовое сообщение) системы электронной почты, рассматриваемого в предыдущем разделе.
Как видите, OCL используется для описания объектов, их состояний и условий.
OCL применяется для точного моделирования, а диаграммы деятель ности по своей природе не могут быть точными. Кроме того, они часто предназначаются для заказчиков, которые не являются специалиста ми в технической области. Поэтому целесообразность применения OCL
на диаграммах этого типа довольно сомнительна. Например, ограни чения на рис. 25.18 могли бы быть записаны просто на естественном языке (английском или русском). Рассматривая возможность исполь зования OCL на диаграммах деятельности, всегда необходимо учиты вать назначение диаграммы и ее целевую аудиторию.
25.11.3. OCL на диаграммах состояний
OCL используется в диаграммах состояний для определения:

сторожевых условий;
:MailSystem classifyMessage( m : Message )
m:Message
:reviewBox alt
:inBox setT ype( Legitimate )
add( m )
[else]
setT ype( Unclassified )
add( m )
sd ClassifyMessage
«delete»
Unclassified
[ blackList >exists( a | a.getAddress() = m.fromAddress.getAddress() ) ]
[ whiteList >exists( a | a.getAddress() = m.fromAddressgetAddress() ) ]
Legitimate
Рис. 25.17. Диаграмма последовательностей для операции
MailSystem::classifyMessage( m : Message )

25.11. OCL на диаграммах других типов
571

условий, налагаемых на состояния;

целей действий;

операций;

значений параметров.
Экземпляр контекста – это экземпляр классификатора, которому при надлежит конечный автомат. В качестве примера рассмотрим конеч ный автомат
CheckingAccountActive (активный текущий счет) класса Che ckingAccount (рис. 25.19).
Из рисунка видно, что на диаграмме синтаксис OCL используется в сто рожевых условиях. Чтобы конечный автомат был рабочим, необходи мо учесть ограничения, которые записаны отдельно, чтобы не загро мождать диаграмму.
context CheckingAccount::balance int:
0
context CheckingAccount inv:
oclInState( InCredit ) implies ( balance >= 0 )
ClassifyMailMessage
GetMailMessage message
[Unclassified]
DeleteMessage
[ whiteList >exists( a | a.getAddress() = m.fromAddress.getAddress() ) ]
ClassifyMessageAsLegitimate message
[Legitimate]
message
[Unclassified]
FileMessageInInBox
FileMessageForReview else else
[ blackList >exists( a | a.getAddress() = m.fromAddress.getAddress() ) ]
Рис. 25.18. Диаграмма деятельностей

572
Глава 25. Введение в OCL
inv:
oclInState( Overdrawn ) implies ( balance <0 )
def:
availableBalance = ( balance + overdraftLimit )
def:
enoughMoney = ( ( availableBalance – amount ) >= 0 )
def:
inCredit = ( balance >= 0 )
Обратите внимание, как с помощью oclInState( InCredit ) организована ссылка на состояние
InCredit. В качестве альтернативы можно было бы прикрепить инвариант (
balance >= 0) прямо к состоянию InCredit в виде примечания.
Operating
InCredit
Overdrawn
AcceptingWithdrawal
RejectingWithdrawal deposit( amount )
H
[enoughMoney]
withdraw( amount )
[notenoughMoney]
withdraw( amount )
Active close closed
CheckingAccountActive
[not inCredit]
[inCredit]
open
Рис. 25.19. Конечный автомат CheckingAccountActive

25.12. Дополнительные вопросы
573
25.12. Дополнительные вопросы
В данном разделе рассматриваются некоторые не часто используемые аспекты OCL:

навигация к и из классов ассоциаций;

навигация по квалифицированным ассоциациям;

унаследованные ассоциации;

OCLMessage.
25.12.1. Навигация к и от классов ассоциаций
Имя класса ассоциации используется для навигации к классу ассоциа ции.
Классы ассоциации обсуждаются в разделе 9.4.5. Осуществить нави гацию к классу ассоциации можно с помощью его имени. Для примера рассмотрим рис. 25.20.
Операцию запроса getJobs() можно представить следующим образом:
context Person::getJobs() : Set(Job)
body:
self.Job
Выражение self.Job возвращает Set всех объектов Job, ассоциированных с данным объектом
Person. Этот Set можно использовать в OCL выраже ниях. Пусть согласно бизнес правилу
Person не может занимать две одинаковые должности (
Job). На OCL это можно описать так:
context Person inv:
человек не может занимать две одинаковые должности self.Job >isUnique( j : Job | j.name )
getEmployee() : Person getEmployer() : Company
Company
1..*
0..*
employer employee
Person
Job
name : String dateOfBirth : Date getAge() : Integer getJobs()
getTotalSalary() : Real name : String description : String salary : Real
Рис. 25.20. Навигация к классу ассоциации по имени

574
Глава 25. Введение в OCL
Предположим, компания (
Company) работает по схеме постепенного со кращения круга служебных обязанностей с приближением пенсион ного возраста, и существует бизнес правило, запрещающее человеку
(
Person) старше 60 занимать более одной должности (Job). На OCL это можно представить следующим образом:
context Person inv:
человек старше 60 может занимать только одну должность
(self.getAge() >60) implies (self.Job >count() = 1)
Чтобы получить общую заработную плату
Person, необходимо сложить его зарплату на каждой должности (
Job):
context Person::getTotalSalary() : Real body:
возвращаем суммарную заработную плату на всех должностях self.Job.salary >sum()
Навигацию от класса ассоциации можно осуществлять как обычно –
с помощью имен ролей на отношениях. Например, вот OCL для опера ций getEmployee() и getEmployer() класса Job:
context Job::getEmployee() : Person body:
self.employee context Job::getEmployer() : Company body:
self.employer
25.12.2. Навигация по квалифицированным ассоциациям
Для навигации по квалифицированной ассоциации после имени роли в квадратных скобках указываются квалификаторы.
Квалифицированные ассоциации обсуждались в разделе 9.4.6. Для навигации по квалифицированной ассоциации после имени роли в квадратных скобках размещается квалификатор (или разделенный запятыми список квалификаторов).
На рис. 25.21 приведена простая модель клуба с различными уровня ми членства. Предположим, существует бизнес правило, согласно ко торому членский ID 00001 всегда зарезервирован за председателем клуба. На языке OCL это можно выразить следующим образом:
context Club inv:
id председателя всегда 00001
self.members['00001'].level = 'Chairman'

25.12. Дополнительные вопросы
575
Здесь видно, как используется квалифицированная ассоциация с оп ределенным значением квалификатора для выбора одного объекта из множества (
Set) self.members.
25.12.3. Унаследованные ассоциации
Рассмотрим модель на рис. 25.22. Она адаптирована из книги [Arlow 1]
и представляет модель единиц измерений и систем единиц.
Есть два разных типа единиц измерения (
Unit): метрические (MetricUnits)
и британские (
ImperialUnits). MetricUnits принадлежат метрической систе ме (
MetricSystem), а ImperialUnits – британской системе (ImperialSystem). Од нако UML модель на рис. 25.22 не отражает этого различия. По сути, в ней определено, что любой
Unit может принадлежать любой системе единиц (
SystemOfUnits). Можно сделать модель более точной, если соз дать подкласс отношения между
SystemOfUnits и Unit, как показано на рис. 25.23.
Это решает проблему, но несколько загромождает диаграмму, и при увеличении числа подклассов
Unit и SystemOfUnits ситуация быстро усу губляется.
clubName : String clubAddress : String
Сlub
club memberld : String
1 1
members
Member
id : String name : String address : String level : String
Рис. 25.21. Модель клуба с различными уровнями членства
SystemOfUnits
Unit
MetricUnit
ImperialUnit
Meter
Centimeter
Foot
Inch system units
1 1..*
ImperialSystem
MetricSystem
Рис. 25.22. Модель единиц измерений и систем единиц

576
Глава 25. Введение в OCL
Более изящный способ решения проблемы – определение OCL ограни чений следующим образом:
context MetricUnit inv:
относится к метрической системе self.system.oclIsTypeOf( MetricSystem )
context ImperialUnit inv:
относится к британской системе self.system.oclIsTypeOf( ImperialSystem )
context MetricSystem inv:
все единицы должны быть разновидностью MetricUnit или одним из его подклассов self.units–>forAll( unit | unit.oclIsKindOf( MetricUnit ) )
context ImperialSystem inv:
все единицы должны быть разновидностью ImperialUnit или одним из его подклассов
Обратите внимание на использование OCL выражений oclIsKindOf(...)
и oclIsTypeOf(...):

oclIsKindOf(...) возвращает true, если тип объекта аналогичен типу,
определенному параметром, или является одним из его подклассов.

oclIsTypeOf(...) возвращает true, если тип объекта точно такой же,
как тип, заданный параметром.
SystemOfUnits
Unit
MetricUnit
ImperialUnit
Meter
Centimeter
Foot
Inch system units
1 1..*
MetricSystem
ImperialSystem
1..*
1 1
1..*
Рис. 25.23. В модель добавлен подкласс отношения между SystemOfUnits и Unit

25.12. Дополнительные вопросы
577
25.12.4. OclMessage
OCL сообщения могут использоваться только в постусловиях.
OCL сообщения могут использоваться только в постусловиях. Они по зволяют делать следующее:

подтвердить отправку сообщения;

подтвердить возвращение сообщения;

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

вернуть коллекцию сообщений, отправленных объекту.
В OCL каждый вызов операции или отправка сигнала – это экземпляр
OclMessage. Он имеет набор операций, приведенный в табл. 25.17.
Таблица 25.17
Есть также две операции, применяемые к сообщениям. Они приведе ны в табл. 25.18.
Таблица 25.18
Если сообщение имеет параметры, с операторами has sent (послан) и get messages (получить сообщения) может использоваться специальный синтаксис. Это позволяет задавать фактические параметры или толь ко типы параметров. Синтаксис описан в табл. 25.19.
Для изучения сообщений в OCL мы используем шаблон Observer (на блюдатель), полностью описанный в книге [Gamma 1].
Операция OclMessage
Семантика
aMessage.isOperationCall() : Boolean
Возвращает true, если сообщение представ ляет вызов операции.
aMessage.isSignalSent() : Boolean
Возвращает true, если сообщение представ ляет отправку сигнала.
aMessage.hasReturned() : Boolean
Возвращает true, если сообщение было вызо вом операции, которая вернула значение.
aMessage.result() : T
Возвращает результат вызванной операции;
T представляет тип возвращаемого значения
Оператор сообщения Имя
Семантика
anObject^aMessage()
has sent
Возвращает true, если aMessage() был от правлен в anObject
Может использоваться только в пост условиях anObject^^aMessage()
get messages
Возвращает
Sequence сообщений aMessa ge(), посланных в anObject

578
Глава 25. Введение в OCL
Таблица 25.19
Простой пример применения шаблона Observer показан на рис. 25.24.
Семантика этого шаблона проста: субъект (
Subject) имеет нуль или бо лее наблюдателей (
Observer). При изменении Subject вызывается его опе рация notify() (уведомить), которая в свою очередь вызывает операцию update() (обновить) каждого прикрепленного к ней Observer. Примером обычного использования этого шаблона может быть обновление экра на при изменении базовых бизнес объектов.
Семантика операций
Subject представлена в табл. 25.20.
Таблица 25.20
Рассмотрим возможные постусловия для операций
Subject, которые могут использовать сообщения.
Согласно табл. 25.20 постусловие
Subject::notify() состоит в том, что Ob server::update() был вызван для каждого присоединенного Observer. На языке OCL это может быть выражено следующим образом:
context Subject::notify( )
1   ...   54   55   56   57   58   59   60   61   62


написать администратору сайта