Лекция

Общая характеристика языка

Классификация ограничений и характеристики OCL

Операции над коллекциями

Практическая работа № 7

Лабораторная работа № 7

Язык Object Constraint Language (OCL)

Общая характеристика языка

Более точный и лаконичный способ формулировки ограничений обеспечивает язык OCL (Object Constraints Language). Вот общая характеристика этого языка.

Из языка UML в OCL заимствованы, в первую очередь, следующие концепции:

· класс, атрибут, операция;

· объект (экземпляр класса);

· ассоциация;

· тип данных (включая набор предопределенных типов Boolean, Integer, Real и String);

· значение (экземпляр типа данных).

Для понимания языка OCL существенны определяемые в UML традиционные для объектных моделей данных различия между объектом некоторого класса и значением некоторого типа:

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

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

· в то же время значение является «чистым значением» в том смысле, что:

o при сравнении двух значений проверяются сами эти значения;

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

В дополнение к скалярным типам данных, заимствованным из UML, в OCL предопределены структурные типы, которые являются разновидностями типов коллекций (collection):

· математическое множество (set), неупорядоченная коллекция, не содержащая одинаковых элементов;

· мультимножество (bag), неупорядоченная коллекция, которая может содержать повторяющиеся элементы-дубликаты;

· последовательность (sequence), упорядоченная коллекция, которая может содержать элементы-дубликаты.

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

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

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

Рассмотрим пример:

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

Ограничение, записанное на естественном языке, неформально, его можно неправильно трактовать (например, что чартерные рейсы должны выполняться старыми самолетами, а регулярные – новыми). Поэтому имеет смысл использовать для записи формальный язык, который не допускает произвольных толкований и имеет стандартный синтаксис и семантику. Таковым является объектный язык ограничений OCL (Object Constraint Language), являющийся одним из расширений UML. С использованием OCL диаграмма будет выглядеть так:

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

Классификация ограничений и характеристики OCL

Классификация ограничений:

· Инвариант класса – условие, которое всегда справедливо для всех экземпляров класса (ключевое слово inv:).

· Предусловие операции – условие, которое должно быть истинно перед выполнением операции (ключевое слово pre:).

· Постусловие операции – условие, истинное всегда после выполнения операции (ключевое слово post:).

· Тело запроса – описание результата операции-запроса, не модифицирующей объекты (ключевое слово body:)

· Начальное значение атрибута или соединения (ключевое слово init:)

· Правило вывода, описывающее производные атрибуты, связи или классы (ключевое слово derive:).

· Определение (ключевое слово def:).

В примере мы описали инварианты класса Рейс.

Характеристики OCL:

· текстовый (невизуальный) язык описания ограничений;

· формальный язык, часть стандарта UML;

· язык со строгой типизацией;

· декларативный язык (для ограничений не определяется конкретная процедура их проверки);

· платформо-независимый.

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

Синтаксис OCL-выражения

<OCL-выражение> ::=

<указание контекста>

[(inv | pre | post | body | init | derive | def) : <тело выражения>]

В записи использованы символы языка БНФ: <> выделяют нетерминалы, ( | ) –вхождение одной из указанных альтернатив, [] вхождение 1 или более раз, {} – вхождение 0 или более раз. Терминалы записаны жирным шрифтом.

Контекст. В любом OCL-выражении указывается определенный контекст. Как правило, контекстом является элемент модели (пакет, класс, атрибут, операция), с которым связано ограничение.

<указание контекста> ::= context <имя элемента модели>

В примере контекстом является класс Рейс.

Для того чтобы сослаться на контекст в теле выражения используется слово self. Чтобы много раз не писать self, оно часто опускается. По смыслу self аналогично this в C++. В примере тип – сокращенная запись self.тип.

В теле выражения используются

· выражения простых типов (boolean, integer, string, real);

· элементы модели, для которой составлено ограничение;

· коллекции.

Логический тип OCL почти таков как в языках программирования. Есть дополнительные операции xor и implies. Приоритет логических операций (кроме not) меньше арифметических и операций сравнения – так проще записывать сложные логические выражения. Целый и вещественный типы также стандартны. Имеются дополнительные операции a.max(b) и a.min(b), возвращающие максимум и минимум из двух чисел. Строки также похожи на строки языков программирования, только их нельзя сравнивать в лексикографическом порядке.

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

context Airline inv: name.toLower = ‘klm’ – здесь ‘klm’ – строка, toLower – стандартная операция над строкой, дающая как результат строку в нижнем регистре. Смысл ограничения: у любого экземпляра класса Airline значение атрибута name, записанное строчным буквами совпадает со строкой ‘klm’.

context Passenger inv: age >= ((9.6 - 3.5)* 3.1).floor implies mature = true – здесь floor – «округление вниз». Смысл ограничения: у любого экземпляра класса Passenger значения атрибутов age и mature таковы, что если age > 18, то mature = true.

Ограничения могут быть указаны на диаграмме в примечании, якорь примечания в таком случае играет роль указателя на контекст.. Например, ограничение context Flight inv: self.duration < 4 может изображаться на диаграмме так:

В OCL употребляются условные выражения:

<условное выражение> ::=

if <логическое выражение> then <выражение>

else <выражение>

endif

Пример: if (x >= 0) then x else – x endif возвращает модуль x или x.abs().

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

Обратите внимание на производные атрибуты в классе Flight (arrivalTime, nrPassengers) и статический атрибут minAge класса Passenger.

Для указания атрибута или операции используется выражение с точкой:

<выражение>.<имя>

context Flight inv: self.maxNrPassengers <= 1000 – в любом рейсе максимальное количество пассажиров не превышает 1000 (использован атрибут объекта – экземпляра класса Flight).

context Flight:maxNrPassengers:Integer init: 1000 – в любом рейсе максимальное количество пассажиров по умолчанию = 1000.

context Passenger inv: self.age >= Passenger::minAge – у любого пассажира возраст больше минимального (использован атрибут age экземпляра класса Passenger и атрибут того же класса minAge).

Примеры с производными атрибутами:

context Flight def: arrivalTime:Time = departTime.plus(duration)

или

context Flight:arrivalTime derive: departTime.plus(duration)

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

Пример определения операции:

context Interval:: equals(i: Interval): Boolean body:

(self.nrOfDays*60+self.nrOfHours)*60+self.nrOfMins =

(i.nrOfDays*60+i.nrOfHours)*60+i.nrOfMins

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

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

context Flight

inv: self.origin <> self.destination

inv: self.origin.name = ‘Amsterdam’ – у любого рейса аэропорт назначения и аэропорт вылета не совпадают, а также аэропорт вылета называется ‘Amsterdam’.

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

context Person inv:

if employer.name = ‘OAO MMM’ then

Job.type = #trainer

else

Job.type = #programmer

endif

Смысл ограничения: у любой персоны, занятой в ‘OAO MMM’, тип работы trainer, у остальных тип работы programmer. То же самое по смыслу ограничение можно записать, используя в качестве контекста класс ассоциаций:

context Job inv:

if employer.name = ‘OAO MMM’ then

self.type = #trainer

else

self.type = #programmer

endif

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

· Set (множество– неупорядоченный набор без повторов) – для экземпляра класса Airport прибывающие рейсы составляют множество объектов Flight.

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

· OrderedSet (упорядоченный набор без повторов) – для экземпляра класса Flight все его пассажиры составляют orderedSet объектов Passenger.

· Sequence (упорядоченный набор с повторами) – для экземпляра класса Flight возрасты всех его пассажиров составляют sequence целых значений.

Операции над коллекциями

В OCL имеется большое количество предопределенных операций над коллекциями (isEmpty, size, includes, union …). Синтаксис: <коллекция> -> <операция>

Операция collect возвращает коллекцию значений, полученных при вычислениях выражения для всех элементов коллекции. Запись: <коллекция>->collect(<выражение>) – здесь и далее круглые скобки и | – символы OCL, а не языка БНФ. Сокращенная запись: <коллекция>.<выражение>

Пример: context Airport inv: self.arrivingFlights -> collect(airLine) -> nonEmpty – для любого аэропорта множество авиакомпаний, выполняющих прибывающие рейсы, не пусто.

Операция select возвращает совокупность тех элементов коллекции, для которых <выражение> истинно. Запись: <коллекция>->select(<выражение>)

Пример: context Airport inv: self.departingFlights->select(duration<4)->notEmpty – для любого аэропорта есть хоть один отправляющийся рейс длительностью менее 4 часов.

Операция forAll возвращает true если <выражение> истинно для всех элементов коллекции. Запись: <коллекция>->forAll(<выражение>)

Пример: context Airport inv: self.departingFlights->forAll(maxNrPassengers < 1000) – для любого аэропорта справедливо, что у любого отправляющегося рейса максимальное количество пассажиров < 1000.

Операция exists возвращает true если хотя бы для одного элемента коллекции <выражение> истинно. Запись: <коллекция>->exists(<выражение>)

Другие операции над коллекциями:

· isEmpty: истина, если коллекция пуста;

· notEmpty: истина, если коллекция непуста;

· size: количество элементов коллекции;

· sum: сумма элементов коллекции чисел;

· count(<элемент>): количество вхождений элемента;

· includes(<элемент>): истина, если <элемент> входит в коллекцию;

· excludes(<элемент>): истина, если <элемент> отсутствует в коллекции;

· includesAll(<коллекция>): истина, если все элементы параметра <коллекция> входят в коллекцию.

Коллекции можно сравнивать на = и <>. Преобразование коллекций к другому виду осуществляется при помощи операций asSet(), asBag(), asOrderedSet(), asSequence(). Преобразование типов осуществляется с помощью операции oclAsType(type). Коллекцию коллекций можно сделать «плоской» с помощью операции flatten(). Примеры ее работы:

Set { Set { 1, 2 }, Set { 2, 3 }, Set { 4, 5, 6 } } à flatten à Set { 1, 2, 3, 4, 5, 6 }

Bag { Set { 1, 2 }, Set { 1, 2 }, Set { 4, 5, 6 } } à flatten à Bag { 1, 1, 2, 2, 4, 5, 6 }

Sequence { Set { 1, 2 }, Set { 2, 3 }, Set { 4, 5, 6 } }à flatten à Sequence { 2, 1, 2, 3, 5, 6, 4 }

Дополнительные возможности OCL:

· result и @pre в постусловиях;

· локальные переменные;

· итераторы;

· наследование;

· указание состояний объектов.

С помощью result в постусловии можно указать, что операция возвращает в качестве результата:

context Airline::servedAirports() : Set(Airport)

pre : --none

post: result = flights.destination->asSet

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

context Passenger::Book(f:Flight)

pre : Flight.nrPassengers < Flight.maxNrPassengers

post: Flight.nrPassengers = Flight.nrPassengers@pre + 1

Конструкция let определяет локальную переменную. Запись:

let <name> : <type> = <expression1> in <expression2>

Пример: context Airport inv: let supportedAirlines : Set(Airline) = self.arrivingFlights ->collect(airLine) in (supportedAirlines ->notEmpty) and (supportedAirlines ->size < 500) – здесь для упрощения логического выражения определена локальная переменная supportedAirlines, представляющая собой коллекцию авиалиний, обслуживающих, прибывающие в аэропорт рейсы. Указано, что для любого аэропорта таких авиалиний должно быть больше нуля, но меньше 500.

Конструкция iterate позволяет описывать нестандартные операции над коллекциями. Запись: <коллекция>->

iterate(<переменная1> : <тип>; <переменная2> : <тип> [= <нач. значение>] | <тело>)

где <переменная1> – параметр итератора, <переменная2> – результат итератора, <тело> – OCL-выражение с <переменная1> и <переменная2>.

Например, ограничение:

context Airline inv: self.flights->select(maxNrPassengers > 150)->notEmpty

идентично:

context Airline inv: self.flights->iterate (f : Flight; answer : Set(Flight) = Set{ } |

if f.maxNrPassengers > 150 then answer->including(f) else answer endif )->notEmpty

Поясним второе OCL-выражение. Для авиалинии будет собрана коллекция всех ее рейсов и на этой коллекции будет запущен итератор. В начале работы результат итератора инициализируется пустым множеством. Затем для каждого рейса f из коллекции, одного за другим, будет вычислено условное выражение, которое добавит в результат лишь те рейсы, maxNrPassengers которых больше 150.

В наследовании ограничений работает принцип подстановки Лисковой (Liskov’s Substitution Principle): «Где может находиться экземпляр суперкласса, туда всегда может быть подставлен экземпляр его любого подкласса.» Это означает, что:

· Инвариант суперкласса наследуется любым подклассом.

· Подклассы могут усиливать инвариант.

· Предусловие может быть ослаблено в подклассе.

· Постусловие может быть усилено в подклассе.

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

context ГрузовойСамолет inv:

Рейс->forAll(r | r.oclIsTypeOf(ГрузовойРейс))

context ПассажирскийСамолет inv:

Рейс->forAll(r | r.oclIsTypeOf(ПассажирскийРейс))

Операция oclInState возвращает истину, если объект находится в определенном состоянии. Пример:

context Bottle inv:

self.oclInState(closed) implies filled = #full

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

Подведем итоги.

· OCL позволяет уточнять модель, формулировать запросы к модели, сохранять при этом свободу реализации.

· Пре- и постусловия OCL позволяют точнее описывать интерфейсы и компоненты.

· Рекомендуется при использовании OCL писать простые ограничения, совместно использовать OCL и естественный язык, применять CASE-средства, поддерживающие OCL (например, из состава Eclipse Model Develepment Tools или Dresden OCL Toolkit).

Практическая работа 7

#### Диаграмма состояний (statechart diagram)

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

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

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

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

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

Приведем пример простейшей диаграммы состояний (рисунок 1):

Рисунок 1 – Пример 1

Думаем, здесь все понятно без лишних слов. А вот более сложный пример (рисунок 2):

Рисунок 2 – Пример 2

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

А вот еще один пример (рисунок 3):

Рисунок 3 – Пример 3

Пример описывает устройство – таймер. Такой прибор может применяться в составе различных реле, например, для отключения телевизора по истечении указанного промежутка времени. Основное его назначение - контроль времени (проверка, не истек ли указанный промежуток), но у него есть еще один режим работы - установка. По истечении указанного промежутка времени или при "сбросе" устройство отключается. В конце концов, о чем мы говорим - вы сами много раз устанавливали слип-таймер в телевизоре или устанавливали опцию "Выключить по завершении" в Nero Burning ROM.

####

Задание:

1. Придумайте свой пример и опишите его, используя диаграмму состояний (statechart diagram).

Лабораторная работа №7

Стереотипы классов и их графическое представление

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

Изменить изображение стереотипа для отдельного класса можно, например, с помощью одной из вложенных операций контекстного меню: Options Stereotype Display (ПараметрыИзображение стереотипа). В качестве примера можно представить изображение класса Транзакция Банкомата в форме специальной графической пиктограммы стереотипа. С этой целью следует выполнить операцию контекстного меню: Options Stereotype DisplayIcon (ПараметрыИзображение стереотипаПиктограмма). Соответствующее графическое изображение стереотипа <<entity>> для класса Транзакция Банкомата в форме пиктограммы будет иметь следующий вид (рис. 4.5, а).

Для сравнения можно выбрать изображение класса Транзакция Банкомата в форме декоративного графического стереотипа. С этой целью выполним операцию контекстного меню: Options Stereotype DisplayDecoration (ПараметрыИзображение стереотипаДекорация). Соответствующее графическое изображение стереотипа <<entity>> для класса Транзакция Банкомата в форме декорации будет иметь следующий вид (рис. 4.5, б).

Рис. 4.5. Графические способы изображения стереотипа <<entity>> для класса Транзакция Банкомата

Изменить изображение стереотипов одновременно для нескольких классов диаграммы можно с помощью одной из вложенных операций главного меню: Format Stereotype Display (ФорматИзображение стереотипов). В этом случае необходимо выделить все классы модели в окне диаграммы классов или в браузере проекта. Для выделения группы классов на диаграмме или в браузере проекта следует, удерживая нажатой клавишу Ctrl или Shift на клавиатуре, последовательно щелкать на их изображении левой кнопкой мыши.

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

Продолжая разработку модели банкомата, добавим на диаграмму второй класс с именем Контроллер Банкомата, для которого в окне спецификации свойств выберем стереотип control (управляющий класс), а в качестве документации введем текст: "Реализует логику функционирования банкомата". При этом атрибуты и операции у данного класса будут отсутствовать. Соответствующий фрагмент диаграммы классов после добавления управляющего класса Контроллер Банкомата будет иметь следующий вид (рис. 4.6).

Рис. 4.6. Фрагмент диаграммы классов модели банкомата после добавления на нее класса Контролер Банкомата

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

Далее следует добавить класс с именем IКонтроллер Банка, для которого выбрать стереотип Interface (Интерфейс), означающий, что банкомат пользуется услугами Банка при обработке своих транзакций. Заметим, что первой буквой в имени этого класса является английское "I", которое служит в языке UML для указания интерфейса. Соответствующий фрагмент диаграммы классов после добавления на нее классов Устройство чтения карточки и IКонтроллер Банка будет иметь следующий вид (рис. 4.7).

### Добавление и редактирование атрибутов классов

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

Добавить атрибут к созданному ранее классу можно одним из следующих способов:

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

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

· С помощью операции контекстного меню Insert (Вставить), вызванного при позиционировании курсора в области открытой вкладки атрибутов в диалоговом окне свойств Class Specification соответствующего класса.

Рис. 4.7. Фрагмент диаграммы классов модели банкомата после добавления на нее классов Устройство чтения карточки и Контролер Банкомата

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

Рис. 5.1. Диалоговое окно спецификации свойств класса после добавления нового атрибута

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

Таблица 5.1. Пиктограммы видимости атрибутов классов
Графическое изображение | Текстовый аналог | Назначение пиктограммы
| Public | Общедоступный или открытый. В нотации языка UML такому атрибуту соответствует знак «+»
| Protected | Защищенный. В нотации языка UML такому атрибуту соответствует знак «#»
| Private | Закрытый. В нотации языка UML такому атрибуту соответствует знак «-»
| Implementation | Реализация. В нотации языка UML такому атрибуту соответствует знак «∼»

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

Для атрибута идентификатор карточки в качестве типа его допустимых значений из вложенного списка Type следует выбрать тип Integer (целочисленный), а для задания квантора видимости следует выбрать в группе Export Control (Управление экспортом) квантор Public. Поскольку начальное значение для данного атрибута не определено, соответствующее поле ввода следует оставить пустым. В секцию документации данного атрибута класса можно ввести поясняющий текст: «Устройство чтения карточки считывает значение этого атрибута с кредитной карточки клиента» и нажать кнопку Apply или OK, чтобы сохранить результаты редактирования этих свойств атрибута. Соответствующее окно спецификации свойств атрибута идентификатор карточки после редактирования его общих свойств будет иметь следующий вид (рис. 5.2).

Рис. 5.2. Диалоговое окно спецификации свойств атрибута идентификатор карточки после его редактирования

Для отдельного атрибута можно также определить дополнительные свойства, доступные для редактирования на вкладке Detail (Подробно) диалогового окна спецификации свойств выбранного атрибута (рис. 5.3).

Рис. 5.3. Диалоговое окно спецификации свойств атрибута идентификатор карточки, открытое на вкладке Detail (Подробно)

На вкладке Detail в группе выбора Containment (Локализация) можно специфицировать условия хранения атрибута у объектов выбранного класса. Для выбора могут быть использованы следующие свойства:

· By value (По значению) - свойство по умолчанию, которое означает, что значения атрибута хранятся в пределах адресного пространства, выделенного для объекта данного класса. Например, если имеется атрибут типа String, то значение этой строки содержится в пределах определения класса.

· By reference (По ссылке) - означает, что значение атрибута хранится вне адресного пространства, выделенного для объекта данного класса, но у объектов класса имеется указатель на этот атрибут.

· Unspecified (Не определен) - означает, что метод локализации данного атрибута не определен. В этом случае при генерации программного кода для данного атрибута по умолчанию выбирается значение By value.

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

### Добавление и редактирование операций классов

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

Добавить операцию к созданному ранее классу можно одним из следующих способов:

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

· С помощью операции контекстного меню: New Operation (НоваяОперация) для класса, выделенного в браузере проекта. В этом случае активизируется курсор ввода в области иерархического представления класса в браузере под именем соответствующего класса.

· С помощью операции контекстного меню Insert (Вставить), вызванного при позиционировании курсора в области открытой вкладки операций в диалоговом окне свойств Class Specification соответствующего класса.

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

Таблица 5.2. Пиктограммы видимости операций классов
Графическое изображение | Текстовый аналог | Назначение пиктограммы
| Public | Общедоступный или открытый. В нотации языка UML такому атрибуту соответствует знак «+»
| Protected | Защищенный. В нотации языка UML такому атрибуту соответствует знак «#»
| Private | Закрытый. В нотации языка UML такому атрибуту соответствует знак «-»
| Implementation | Реализация. В нотации языка UML такому атрибуту соответствует знак «∼»

В контексте рассматриваемой модели банкомата в качестве имени первой операции для класса Транзакция Банкомата следует задать: создать новую транзакцию. При этом скобки при задании имени операции не записываются, поскольку программа IBM Rational Rose 2003 добавляет их автоматически. Однако, следуя правилам именования операций в языке UML, в тексте имена операций будут указываться со скобками.

Каждая из операций классов имеет собственное диалоговое окно спецификации свойств Operation Specification, которое может быть открыто по двойному щелчку на имени операции на соответствующей вкладке спецификации класса или на имени этой операции в браузере проекта. Для операции создать новую транзакцию() в качестве квантора видимости следует выбрать из вложенного списка квантор public. В секцию документации данной операции класса можно ввести поясняющий текст: «Вызывается после того, как кредитная карточка вставлена в Устройство чтения карточки» и нажать кнопку Apply или OK, чтобы сохранить результаты редактирования свойств этой операции. Соответствующее окно спецификации свойств операции создать новую транзакцию() после редактирования ее свойств будет иметь следующий вид (рис. 5.4).

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

Рис. 5.4. Диалоговое окно спецификации свойств операции создать новую транзакцию()

Рис. 5.5. Диалоговое окно спецификации свойств операции создать новую транзакцию(), открытое на вкладке Detail (Подробно)

На вкладке Detail в многостраничном поле Arguments (Аргументы) можно определить аргументы редактируемой операции. Для этого следует выполнить операцию контекстного меню Insert (Вставить). После этого в этом поле появится аргумент данной операции с именем по умолчанию argname. Для редактирования свойств аргумента предназначено специальное окно свойств аргумента.

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

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

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

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

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

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

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

### Спецификация атрибутов и операций для класса Транзакция Банкомата

Чтобы закончить спецификацию класса Транзакция Банкомата аналогичным способом следует добавить еще 3 атрибута и 2 операции со следующими свойствами:

· значение ПИН-кода карточки с квантором видимости public. В качестве типа этого атрибута следует выбрать тип Integer (целочисленный), а в секцию документации атрибута ввести поясняющий текст: «Устройство чтения карточки считывает значение этого атрибута с кредитной карточки клиента».

· введенный ПИН-код с квантором видимости public. В качестве типа этого атрибута следует выбрать тип Integer (целочисленный), а в секцию документации атрибута ввести поясняющий текст: «Значение этого атрибута вводится клиентом с клавиатуры банкомата».

· введенная сумма наличных с квантором видимости public. В качестве типа этого атрибута следует выбрать тип Currency (Денежный), а в секцию документации атрибута ввести поясняющий текст: «Значение этого атрибута вводится клиентом с клавиатуры банкомата».

· проверить правильность ПИН-кода() с квантором видимости public. В качестве типа возвращаемого результата для этой операции следует выбрать тип Boolean (логический), а в секцию ее документации ввести поясняющий текст: «Вызывается после того, как клиент ввел значение ПИН-кода с клавиатуры банкомата».

· завершить транзакцию() с квантором видимости public. В секцию ее документации ввести поясняющий текст: «Вызывается после завершения всех действий банкомата по обслуживанию клиента».

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

Рис. 5.6. Фрагмент диаграммы классов модели банкомата после добавления атрибутов и операций для класса Транзакция банкомата

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