04 (1158683), страница 2
Текст из файла (страница 2)
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 }
Дополнительные возможности 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).
6