UML2 и унифицированный процесс. Джим арлоуайла нейштадтпрактический объектно ориентированныйанализ и проектированиеu
![]()
|
547 Учитываются ограничения и исходной, и результирующей коллек ции. В данном случае исходная коллекция является неупорядочен ной. Но результирующая коллекция упорядочена, поскольку опера ция закрепляет этот произвольный порядок для результирующей кол лекции. 25.8.6.3. Операции сравнения Операции сравнения (табл. 25.10) сравнивают целевую коллекцию с коллекцией параметром того же типа и возвращают результат типа Boolean. Эти операции учитывают ограничения упорядочения коллек ций. Таблица 25.10 25.8.6.4. Операции запроса Операции запроса (табл. 25.11) позволяют получить информацию о кол лекции. Таблица 25.11 Операции сравнения Операция над коллекциями Семантика X(T)::=( y : X(T) ) : Boolean Set и Bag возвращают true, если в y содержат ся такие же элементы, как в целевой кол лекции. OrderedSet и Sequence возвращают true, если в y содержатся такие же элементы и в том же порядке, как в целевой коллекции. X(T)::<>( y : X(T) ) : Boolean Set и Bag возвращают true, если в y не содер жатся такие же элементы, как в целевой коллекции. OrderedSet и Sequence возвращают true, если в y не содержатсятакие же элементы, располо женные в том же порядке, как в целевой коллекции. Операции запроса Операция над коллекциями Семантика X(T)::size() : Integer Возвращает количество элементов в целевой коллекции X(T)::sum() : T Возвращает сумму всех элементов целевой коллекции Тип T должен поддерживать оператор + X(T)::count( object : T ) : Integer Возвращает количество object в целевой кол лекции X(T)::includes( object : T ) : Boolean Возвращает true, если целевая коллекция со держит object 548 Глава 25. Введение в OCL Таблица 25.11 (продолжение) 25.8.6.5. Операции доступа Только упорядоченные коллекции OrderedSet и Sequence обеспечивают возможность прямого доступа к своим элементам по их положению в коллекции (табл. 25.12). Чтобы организовать доступ к элементам не упорядоченных коллекций, необходимо перебрать все элементы кол лекции от начала до конца. Таблица 25.12 25.8.6.6. Операции выбора Операции выбора (табл. 25.13) возвращают новые коллекции, являю щиеся подмножествами или надмножествами целевой коллекции. Мы воспользовались диаграммами Венна (Venn) для иллюстрации опера ций с множествами: объединения, пересечения, строгой дизъюнкции и дополнения. Операции запроса Операция над коллекциями Семантика X(T)::excludes( object : T ) : Boolean Возвращает true, если целевая коллекция не содержит object X(T)::includesAll( c : Collection(T) ) : Boolean Возвращает true, если в целевой коллекции содержатся все элементы c X(T)::excludesAll( c : Collection(T) ) : Boolean Возвращает true, если в целевой коллекции не содержатся элементы c (если хотя бы один элемент с содержится в целевой коллекции, результат – false). X(T)::isEmpty() : Boolean Возвращает true, если целевая коллекция пуста, в противном случае возвращает false X(T)::notEmpty() : Boolean Возвращает true, если целевая коллекция не пуста, в противном случае возвращает false Операции доступа Операция над коллекциями Семантика OrderedSet(T)::first() : T Sequence(T)::first() : T Возвращает первый элемент коллекции OrderedSet(T)::last() : T Sequence(T)::last() : T Возвращает последний элемент коллекции OrderedSet::at( i ) : T Sequence::at( i ) : T Возвращает элемент в позиции i OrderedSet::indexOf( T ) : Integer Возвращает индекс объекта параметра в Orde redSet 25.8. Тело выражения 549 Таблица 25.13 Операции выбора Операция над коллекциями Семантика X(T)::union( y : X(T) ) : X(T) Возвращает новую коллекцию, ко торая является результатом присо единения y к целевой коллекции; тип новой коллекции всегда соот ветствует типу целевой коллекции. Дублирующиеся элементы удаля ются, порядок устанавливается в случае необходимости. Set(T)::intersection( y : Set(T) ) : Set(T) OrderedSet(T)::intersection( y : OrderedSet(T) ) : OrderedSet(T) Возвращает новую коллекцию, со держащую элементы, присутствую щие и в y, и в целевой коллекции. Set(T)::symmetricDifference( y : Set(T) ) : Set(T) OrderedSet(T)::symmetricDifference( y : Order edSet(T) ) : OrderedSet(T) Возвращает новый Set, содержащий элементы, которые существуют в це левой коллекции и в y, но не в обеих. Set(T):: ( y : Set(T) ) : Set(T) OrderedSet(T):: ( y : OrderedSet(T) ) : Ordered Set(T) Возвращает новый Set, содержащий все элементы целевой коллекции, которых нет в y. В теории множеств возвращаемое множество является дополнением a относительно b. X(T)::product( y : X(T2) ) : Set( Tuple( first : T, second : T2 ) ) Возвращает декартово произведение целевой коллекции и y – это Set объ ектов Tuple{ first=a,second=b }, где a – член целевой коллекции, а b – член y например Set{ 'a',' b' } >product( Set { '1','2' } ) y target target y target y target y 550 Глава 25. Введение в OCL Таблица 25.13 (продолжение) 25.8.7. Итерационные операции Итерационные операции позволяют циклически перебирать элементы коллекции. Их общая форма показана на рис. 25.7. Слова в угловых скобках ( <...>) должны быть заменены соответствую щими величинами. Слова, выделенные серым цветом, обозначают не обязательные части. Операции выбора Операция над коллекциями Семантика возвращает Set{ Tuple{ first='a', second='1' }, Tuple{ first='a',second='2' }, Tuple{ first='b', second='1' }, Tuple{ first='b',second='2' } } X(T)::including( object : T ) : X(T) Возвращает новую коллекцию, вклю чающую содержимое целевой коллек ции плюс object. Если коллекция упорядочена, object добавляется в ее конец. X(T)::excluding( object : T ) : X(T) Возвращает новую коллекцию, в ко торой удалены все вхождения object. Sequence(T)::subSequence( i : Integer, j : In teger ) : Sequence(T) Возвращает новый Sequence, в кото рый входят элементы целевой коллек ции, начиная от элемента с индексом i, заканчивая элементом с индексом j. OrderedSet::subOrderedSet ( i : Integer, j : In teger ) : OrderedSet(T) Возвращает новый OrderedSet, в кото рый входят элементы целевого Ordered Set, начиная с элемента с индексом i, заканчивая элементом с индексом j. OrderedSet(T)::append( object : T ) : Ordered Set(T) Sequence(T)::append( object : T ) : Sequen ce(T) Возвращает новую коллекцию с object, добавленным в конце. OrderedSet(T)::prepend( object : T ) : Ordered Set(T) Sequence(T)::prepend( object : T ) : Sequen ce(T) Возвращает новую коллекцию с object, добавленным в начале. OrderedSet(T)::insertAt( index : Integer, ob ject : T ) : OrderedSet(T) Sequence(T)::insertAt( index : Integer, ob ject : T ) : Sequence(T) Возвращает новую коллекцию с object, вставленным в позицию по указанно му индексу. 25.8. Тело выражения 551 Операции итератора работают следующим образом: операцияИтератора поочередно посещает каждый элемент коллекции. Текущий элемент представлен переменнойИтератора. Выражение выражениеИтератора при меняется к переменнойИтератора для получения результата. Каждая опе рацияИтератора обрабатывает результат по своему. Указывать Тип переменной итератора необязательно, поскольку он все гда аналогичен типу элементов коллекции. Сама переменнаяИтератора яв ляется необязательной. Когда выбран любой из элементов коллекции, все его возможности автоматически доступны выражениюИтератора. Доступ к ним может осуществляться напрямую по имени. Например, если элемент является объектом BankAccount, имеющим атрибут balance, выражениеИтератора может ссылаться непосредственно на balance. Однако отсутствие в записи переменнойИтератора может быть чревато не приятностями. Мы считаем это плохим стилем, поскольку выражение Итератора сначала ищет все необходимые ему переменные в своем про странстве имен, а если не может найти переменную, ищет в окружаю щих пространствах имен. Если переменнаяИтератора пропущена, суще ствует опасность, что выражениеИтератора обнаружит не то, что надо. Мы разделили операции итератора на логические операции (возвра щающие значение типа Boolean) и операции выбора (возвращающие выборку из коллекции). Все операции представлены в табл. 25.14. Таблица 25.14 Логические операции итератора Семантика X(T)::exists( i : T | iteratorExpression ) : Boo lean Возвращает true, если выражение ите ратора ( iteratorExpression) принимает значение true, по крайней мере, для одного значения i, в противном случае возвращает false. X(T)::forAll( i : T | iteratorExpression ) : Boo lean Возвращает true, если iteratorExpression принимает значение true для всех зна чений i, в противном случае возвра щает false. X(T)::forAll( i : T, j : T ..., n : T | iteratorExpres sion ) : Boolean Возвращает true, если iteratorExpression принимает значение true для каждого { i, j ... n } Tuple, в противном случае возвращает false. Множество пар { i, j ... n } – это декар тово произведение целевой коллекции с самой собой. коллекция ><операцияИтератора>( переменнаяИтератора> : <Тип> | < выражениеИтератора> ) Рис. 25.7. Общая форма итерационных операций 552 Глава 25. Введение в OCL Таблица 25.14 (продолжение) Стоит поближе рассмотреть forAll(...). Данная операция имеет две фор мы. Первая форма – с одной переменной итератора (iteratorVariable), вто рая – с множеством. Вторая форма является сокращенной записью не скольких вложенных операций forAll(...). Например, рассмотрим две вложенные операции forAll(...): c >forAll( i | c >forAll( j | iteratorExpression ) ) Логические операции итератора Семантика X(T)::isUnique( i : T | iteratorExpres sion ) : Boolean Возвращает true, если iteratorExpression имеет уникальное значение для каждого значе ния i, в противном случае возвращает false. X(T)::one( i : T | iteratorExpression ) : Boolean Возвращает true, если iteratorExpression при нимает значение true только для одного зна чения i, в противном случае возвращает false. Операции выбора для итератора Семантика X(T)::any( i : T | iteratorExpression ) : T Возвращает случайный элемент целевой коллекции, для которого iteratorExpression имеет значение true. X(T)::collect( i : T | iteratorExpression ) : Bag(T) Возвращает Bag, содержащий результаты однократного выполнения iteratorExpression для каждого элемента целевой коллекции (нотацию краткой записи collect(...) см. в разделе 25.9.2). X(T)::collectNested( i : T | iteratorEx pression ) : Bag(T) Возвращает Bag коллекций, содержащий результаты однократного выполнения itera torExpression для каждого элемента целевой коллекции. Поддерживает вложение целевой коллек ции в результирующую коллекцию. X(T)::select( i : T | iteratorExpression ) : X(T) Возвращает коллекцию, содержащую эле менты целевой коллекции, для которых iteratorExpression принимает значение true. X(T)::reject( i : T | iteratorExpression ) : X(T) Возвращает коллекцию, содержащую эле менты целевой коллекции, для которых iteratorExpression принимает значение false. X(T)::sortedBy( i : T | iteratorExpres sion ) : X(T) Возвращает коллекцию, содержащую эле менты целевой коллекции, упорядоченные соответственно iteratorExpression. Тип переменной итератора (iteratorVariable) должен быть типом, в котором определен оператор <. 25.8. Тело выражения 553 Они могут быть записаны следующим образом: c >forAll( i, j | iteratorExpression ) Результатом применения обеих форм записи операции является пере бор множества пар { i, j }, т. е. декартово умножение c на саму себя. Проясним это с помощью примера. Пусть c = Set{ x, y, z } Декартовым произведением c с самой собой является Set { {x,x}, {x,y}, {x,z}, {y,x}, {y,y}, {y,z}, {z,x}, {z,y}, {z,z} } Затем c >forAll( i, j | iteratorExpression ) осуществляет перебор каждого под множества этого Set, присваивая каждому i и j по одному элементу под множества. После этого i и j можно использовать в выражении итера тора. Мы полагаем, что форма forAll(...) с несколькими параметрами может сбить с толку, и ее применения следует избегать. Все эти итерационные операции (кроме forAll(...) с несколькими пара метрами) являются особыми случаями более общей операции iterate, которая рассматривается в следующем разделе. 25.8.7.1. Операция iterate С помощью OCL операции iterate можно создавать собственные специ альные итерации. Ее форма представлена на рис. 25.8. Как видим, кроме переменнойИтератора и ее Типа (который в данном слу чае является обязательным) здесь присутствует результирующаяПере менная, тип которой может отличаться от типа переменнойИтератора. ре зультирующаяПеременная получает начальное значение от выраженияИни циализации, а ее конечное значение формируется в результате последо вательных применений выраженияИтератора. Принцип работы операции iterate следующий. выражениеИнициализации инициализирует результирующуюПеременную некоторым значением. За тем операция iterate выполняет выражениеИтератора для каждого члена коллекции по очереди, используя переменнуюИтератора и текущее значе ние результирующейПеременной. Результатом вычисления выраженияИте ратора становится новое значение результирующейПеременной, которое используется при выполнении выраженияИтератора для следующего эле мента коллекции. Значение операции iterate(...) – это конечное значе ние результирующейПеременной. коллекция > iterate( <переменнаяИтератора> : <Тип> <результирующаяПеременная> : <РезультирующийТип> = <выражениеИнициализации> | <выражениеИтератора> ) Рис. 25.8. Форма операции iterate 554 Глава 25. Введение в OCL Вы легко усвоите принцип действия операции iterate из следующего примера: Bag{ 1, 2, 3, 4, 5 } >iterate( number : Integer; sum : Integer = 0 | sum + number ) В результате этого выражения получаем сумму чисел в Bag. В данном случае она равняется 15. Это абсолютно эквивалентно следующей опе рации: Bag{ 1, 2, 3, 4, 5 } >sum() Операция iterate – самый универсальный итератор. Она может исполь зоваться для моделирования всех остальных итераторов. Ниже приве ден пример, который выбирает все положительные числа множества ( Set). Set{ 2, 3, 1, 2 } >iterate( number : Integer; positiveNumbers : Set(Integer) = Set{} | создаем пустой Set if number >= 0 then пропускаем отрицательные числа positiveNumbers >including( number ) добавляем число в конец результирующего Set else positiveNumbers просто возвращаем resultVariable endif ) Это абсолютно эквивалентно следующему: Set{ 2, 3, 1, 2 } >select( number : Integer | number >= 0 ) 25.9. Навигация в OCL Навигация – это способность перемещаться от исходного объекта к од ному или более целевым объектам. Навигация – это процесс, при помощи которого можно проследить связи от исходного объекта к одному или более целевым объектам. Навигация – вероятно, самый сложный и запутанный вопрос OCL. До сих пор для написания OCL выражения необходимо было знать путь от контекста выражения к другим элементам модели, на которые надо сослаться. Это означает, что OCL должен использоваться как навига ционный язык. Навигационные выражения OCL могут ссылаться на любое из следую щего: • классификаторы; 25.9. Навигация в OCL 555 • атрибуты; • концы ассоциаций; • операции запроса (операции, свойство isQuery которых имеет значе ние true). В спецификации OCL [OCL1] их называют свойствами. В следующем разделе рассматривается простая навигация в рамках экземпляра контекста, а далее – навигация по отношениям с кратно стью 1 и больше 1. 25.9.1. Навигация в рамках экземпляра контекста Давайте рассмотрим простой пример навигации для доступа к возмож ностям экземпляра контекста. На рис. 25.9 показан класс A с единст венным атрибутом a1 и единственной операцией op1(). Предполагая, что класс A является контекстом выражения, можно на писать навигационные выражения OCL, перечисленные в табл. 25.15. Таблица 25.15 Здесь необходимо отметить несколько важных моментов. • Доступ к экземпляру контекста осуществляется с помощью ключе вого слова self. • Доступ к свойствам экземпляра контекста осуществляется напря мую или с помощью ключевого слова self и оператора «точка». При держиваясь хорошего стиля, мы предпочитаем явно использовать self и оператор «точка». • Единственные операции, к которым можно организовать доступ, – операции запроса. Навигационное выражение Семантика self Экземпляр контекста – экземпляр класса A self.a1 a1 Значение атрибута a1 экземпляра контекста self.op1() op1() Результат вызова op1() экземпляра контекста Операция op1() должна быть операцией запроса A a1:String op1():String Рис. 25.9. Класс А с одним атрибутом и одной операцией 556 Глава 25. Введение в OCL 25.9.2. Навигация по ассоциациям Навигация по ассоциациям немного сложнее. Обычно навигацию можно осуществлять только по ассоциациям, допускающим навига цию, и можно получать доступ только к открытым возможностям классов. Однако спецификация OCL позволяет интерпретатору OCL иметь необязательную возможность проходить не допускающие нави гацию ассоциации и получать доступ к закрытым и защищенным свойствам. Возможности используемого для обработки OCL выраже ния интерпретатора OCL необходимо сверять по спецификации. На рис. 25.10 представлены некоторые выражения навигации по ассо циации между двумя классами A и B, где кратность на конце b равна 1. Для навигации по ассоциациям необходимо использовать оператор «точка». Навигация по ассоциации осуществляется с помощью оператора «точ ка» так, как если бы имя роли являлось атрибутом контекстного клас са. Выражение навигации может возвращать объект (или объекты), находящийся на целевом конце, значения его атрибутов и результаты его операций. Семантика навигации зависит от кратности на целевом конце ассоциации. Навигация усложняется, когда кратность на целевом конце ассоциа ции больше 1, потому что семантика навигации зависит от кратности. На рис. 25.11 показаны некоторые выражения для навигации по ассо циации между двумя классами C и D, где кратность на конце d – много. Навигационное выражение self.d возвращает Set(D) объектов d. Это означает, что оператор «точка» перегружен. Когда кратность на це левом конце равна 1 или 0..1, он возвращает объект того же типа, что A a1:String B b1:String 1 b op1():String self self.b self.b.b1 self.b.op1() Экземпляр контекста – экземпляр А Объект типа В Значение атрибута B::b1 Результат операции B::op1() Навигационные выражения (A контекст выражения) Выражение Значение Пример модели контекст |