-1-
ambas clases participantes en la asociacin, que deben estar rotulados (en ambos extremos). El
rol de una segunda clase en una asociacin con la clase, expresa que ese rol es un
pseudoatributo del tipo de dato vinculado a la clase original.
Como se puede ver, todos los componentes asociados a las clases, tambin se ven reflejados en
los tipos de OCL.
Las expresiones del lenguaje OCL se estructuran hasta llegar a su punto ms alto, que es el
de formar parte de una definicin. En cada definicin de OCL se describe cada restriccin
semntica del diagrama de clases, junto a otras propiedades tambin descriptas con expresiones.
Cada definicin en OCL se aplica a lo que se llama un contexto, que representa el destinatario
del diagrama de clases sobre quien se aplica esa definicin. Entre estos contextos se encuentran:
- Una clase (se aplica a todas expresiones-objetos cuyo tipo de datos asociado es el
vinculado a esta clase).
- Un mtodo/responsabilidad de una clase.
- Un atributo derivado de una clase.
- Un mtodo/responsabilidad derivado (tambin llamado query) de una clase.
En OCL se permite utilizar recursin en todas las definiciones que se necesiten.
Tipos de definiciones
1) Invariantes
context idclase
inv: [[Descripcin del invariante]] expBool
Representa una condicin (restriccin semntica) que deben cumplir todas las expresionesobjetos pertenecientes al tipo de datos vinculados a la clase idclase. La condicin a cumplirse se
expresa en la expresin expBool que es de tipo Boolean (lgico). La expresin booleana debe
evaluar en verdadero si se aplica a expresiones-objetos pertenecientes al tipo de la clase en
cuestin que son vlidos bajo este invariante. Para el resto de las expresiones-objetos (que son
invlidas segn este invariante), la expresin debe evaluar en falso.
Estos invariantes pueden tener una descripcin optativa (que se escribe entre corchetes).
En la prctica se podr observar que el mismo invariante (que en realidad no es de una clase
ni de una expresin-objeto, sino del modelo propiamente dicho) se puede describir partiendo de
diferentes contextos, aunque por supuesto, la dificultad de expresarlo puede ser mayor si se
opta por un contexto inadecuado.
2) Invariantes (definiciones) de mtodo/responsabilidad
context idclase::idmetodo([out|in/out] par1:T1,...,[out|in/out] parn:Tn)[:Tres]
pre: [[Descripcin precondicin]] expBool
especifica cul ser el valor retornado para cada expresin-objeto de la clase que sea aplicable,
a travs de la expresin expT, que ser de tipo T.
Tipos de datos
1) Predefinidos
a) Bsicos
- Boolean (valores lgicos)
- Integer (valores enteros)
- Real (valores reales)
- String (valores de cadenas de caracteres)
- OCLAny (el tipo supremo jerrquico de todos los tipos no estructurados)
- OCLType (el tipo asociado a los metatipos -todo tipo puede verse como una
expresin de tipo OCLType-)
b) Estructurados
- Collection(T)
- Set(T)
- Bag(T)
- OrderedSet(T)
- Sequence(T)
- Tuple{id1:T1,..., idn:Tn}
El tipo Set(T) corresponde a los conjuntos de expresiones de tipo T, que no contienen
repeticiones y sus expresiones contenidas no poseen un orden posicional.
El tipo Bag(T) corresponde a los bags de expresiones de tipo T, que permiten contener
repeticiones y donde sus expresiones contenidas no poseen un orden posicional.
El tipo OrderedSet(T) corresponde a los conjuntos ordenados de expresiones de tipo
T, que no contienen repeticiones y sus expresiones contenidas poseen un orden posicional.
El tipo Sequence(T) corresponde a las secuencias (listas) de expresiones de tipo T, que
permiten contener repeticiones y donde sus expresiones poseen un orden posicional.
El tipo Collection(T) corresponde a las colecciones de expresiones de tipo T. Es un
tipo que es abstracto y superior jerrquico de los cuatro anteriores.
El tipo Tuple{id1:T1,..., idn:Tn} (con n>0) corresponde a las tuplas
(registros/records) con campos de nombre id1 a idn , donde cada uno de ellos debe tener
asociada una expresin de tipo T1 a Tn respectivamente.
2) No predefinidos
Corresponden a cada clase y enumerado del diagrama de clases. Toda clase o enumerado C
se mapear al tipo asociado TC de OCL. Sin embargo, como abuso de notacin es normal
referirse al tipo como C (el mismo nombre de la clase), aunque no lo haremos en el resto de
este apunte. Aqu expresamos al tipo de la clase C como TC slo a los efectos de distinguir la
diferencia de conceptos entre clase y tipo.
En OCL cada atributo de una clase, al aplicarse a una expresin del tipo asociado a la clase,
retorna una expresin que tambin tendr un tipo asociado. Con esto, decimos que todo atributo
tiene tambin un tipo asociado. Esto ya se dijo en la definicin de atributos derivados, cuando
se expres que stos retornan una expresin de un tipo resultante especificado. Con esto,
decimos que todo atributo atrib tiene asociado en OCL el tipo de dato Tatrib. Este tipo no es
necesariamente nuevo (como en el caso de los provenientes de clases o enumerados). Al no
definir un tipo necesariamente nuevo, en este apunte diremos que el tipo retornado es T.
Si utilizamos el diagrama de clases dentro del contexto del diseo, seguramente cada
atributo de cada clase tendr su tipo de datos asociado en forma explcita en la misma clase del
diagrama, y con esto se puede mapear al tipo correspondiente de OCL. El problema que existe
en el diagrama de clases del modelo conceptual es que en las clases conceptuales no se
especifican tipos de datos. Esto sugiere la idea de existencia de dominios -como abstracciones
respecto a los tipos- (los atributos de las clases conceptuales retornan un objeto de un dominio,
en lugar de una expresin-objeto de un tipo de datos). En este caso hay que realizar un mapeo
implcito de los dominios de los atributos a tipos bsicos de OCL para poder expresar
condiciones en OCL que se apliquen sobre los valores retornados por estos atributos.
Retorna la interseccin de dos colecciones. Se asume que si alguna de las dos es de un tipo
que no admite repeticiones, entonces la coleccin retornada no podr contener repeticiones.
Set(Collection(T))->flatten(): Set(T)
Bag(Collection(T))->flatten(): Bag(T)
OrderedSet(Collection(T))->flatten(): OrderedSet(T)
Sequence(Collection(T))->flatten(): Sequence(T)
Retorna el aplanado de una coleccin de colecciones, eliminando un nivel de colecciones.
Dicho de otra forma, retorna la concatenacin de todos los elementos de la coleccin de
colecciones original (que son colecciones). El tipo mandatorio de la coleccin resultante es el
ms externo.
Las siguientes operaciones son de orden superior, ya que como parmetro de estas
operaciones se especifican funciones implcitas representadas por una variable ligada (bounded
variable) y una expresin-cuerpo que admite apariciones libres de la variable ligada
especificada (y que hace referencia a ella misma).
Collection(T)->forAll(var | exp: Boolean): Boolean
Retorna si todos los elementos de la coleccin original cumplen con la condicin dada. La
condicin se expresa en el parmetro de esta operacin, usando una variable ligada (var) que se
instancia con cada elemento de la coleccin, y la condicin a testear sobre cada uno de ellos
(expresin lgica exp). Esta expresin exp admite apariciones libres de la variable var.
Collection(T)->forAll(var1, var2 | exp: Boolean): Boolean
Retorna lo mismo que la siguiente expresin (suponiendo que c es una expresin de tipo
Collection(T)):
c->forAll(var1 | c->forAll(var2 | exp))
Collection(T)->exists(var | exp: Boolean): Boolean
Retorna si alguno de los elementos de la coleccin original cumple con la condicin dada.
La condicin se expresa en el parmetro de esta operacin, usando una variable ligada (var) que
se instancia con cada elemento de la coleccin, y la condicin a testear sobre cada uno de ellos
(expresin lgica exp). Esta expresin exp admite apariciones libres de la variable var.
Set(T)->select(var | exp: Boolean): Set(T)
Bag(T)->select(var | exp: Boolean): Bag(T)
OrderedSet(T)->select(var | exp: Boolean): OrderedSet(T)
Sequence(T)->select(var | exp: Boolean): Sequence(T)
Retorna a todos los elementos de la coleccin original que cumplen con la condicin dada en
el parmetro. La variable ligada var se vincula a cada elemento de la condicin, y la expresin
res := expinicial
paraCada i indice de c
(0 i size(c)-1, creciente)
res := ((var1, var2) exp) (c[i],res)
fin-paraCada
retornar res
la expresin de la parte derecha de la asignacin del rengln 3 significa la aplicacin de una
funcin de dos parmetros. Se espera que tanto var1 como var2 existan como subexpresiones de
exp (aunque esto puede no ser as).
Esta operacin es anloga al mtodo tambin llamado collect del lenguaje orientado a
objetos Smalltalk, y a la funcin foldl del lenguaje funcional Haskell.
Todas las operaciones de coleccin que reciben parmetros de la forma (var | exp) (como
forAll, exists, select, reject, collect y isUnique) pueden ser escritos con otra
sintaxis, a saber:
Collection(T)->operacion(var | exp)
Collection(T)->operacion(var: T2 | exp)
Collection(T)->operacion(exp)
El segundo caso es anlogo al primero, con la diferencia que se agrega el tipo de la variable
ligada var. Este tipo aqu especificado T2 slo puede ser T (el tipo de la coleccin) o un subtipo
de T. En el caso que se indique que este tipo T2 es T, estamos en un caso idntico al primer caso
(donde el tipo de la variable ligada var es T). Pero si se indicara que este tipo es un subtipo de
T, expresamos que dentro de la expresin exp se puede realizar un typecast sobre el tipo T por
este subtipo T2 para las apariciones de la variable-expresin var (similar al uso de la operacin
OCLasType). Los vnculos de variables reconocidos en la expresin exp son los reconocidos
por el contexto de la expresin general ms la variable var. El uso de typecasts y de la
operacin OCLasType se comentar despus.
En el tercer caso, la variable var no aparece, y no puede aparecer libre como subexpresin de
la expresin exp. En exp todos los mtodos/responsabilidades, atributos y pseudoatributos
aplicados a un receptor no especificado, son asumidos que se aplican en primera instancia a
cada elemento de la coleccin, y en segunda instancia, a self. Si hubiera algn problema de
ambigedad, no se puede elegir esta opcin de sintaxis, y se debe optar por alguna de las dos
primeras.
Como caso aparte, en la operacin forAll con el iterador sobre pares de elementos de la
coleccin dada, la expresin lgica del cuerpo del mtodo/responsabilidad puede contener
apariciones libres de estas dos variables ligadoras, y que se ligaran a todos los pares de
elementos.
Notacin de punto aplicada a colecciones:
c->collect(psatrib)
c->collect(psatrib)->flatten()
c.psatrib
Jerarqua de tipos
Los tipos de datos se encuentran jerarquizados a travs del concepto de inclusin. Los tipos
includos
heredan
todas
las
propiedades
(atributos,
peudoatributos
y
mtodos/responsabilidades) de sus tipos superiores (los que lo incluyen). La relacin de
inclusin estricta este tipos se refleja con el siguiente operador:
T1 < T2 def T1 es un subtipo estricto de T2
Las reglas propias del operador < de inclusin de tipos son las siguientes:
- Si A es una clase y B es una subclase de A en el diagrama de clases, entonces TB < TA
- T < OCLAny (para todo tipo T no estructurado)
- T1 < T2 Set(T1) < Set(T2)
- T1 < T2 Bag(T1) < Bag(T2)
- T1 < T2 OrderedSet(T1) < OrderedSet(T2)
- T1 < T2 Sequence(T1) < Sequence(T2)
- Set(T) < Collection(T)
- Bag(T) < Collection(T)
- OrderedSet(T) < Collection(T)
- Sequence(T) < Collection(T)
- T < T Tuple{id1:T1,...,idi:T,...,idn:Tn} <
Tuple{id1:T1,...,idi:T,...,idn:Tn}
- Integer < Real
- T1 < T2 y T2 < T3 T1 < T3
- T : OCLType
(en realidad, aqu no se especifican jerarquas)
Las reglas de la herencia implcita por la existencia del operador jerrquico < de inclusin de
tipos son las siguientes:
Sea TA < TB, y las expresiones expA y expB de tipos TA y TB respectivamente.
a) Si es vlida la expresin expB.attrib que retorna una expresin de tipo T,
(obtencin de un atributo), entonces tambin ser vlida la expresin expA.attrib,
tambin retornando una expresin de tipo T, autodefinida anlogamente a la anterior.
b) Si es vlida la expresin expB.psattrib que retorna una expresin de tipo T,
(obtencin de un pseudoatributo), entonces tambin ser vlida la expresin
expA.psattrib, tambin retornando una expresin de tipo T, autodefinida
anlogamente a la anterior.
c) Si es vlida la operacin expB.met(exp1,...,expn) con expresiones-parmetros
exp1 a expn que son de tipo T1 a Tn respectivamente (aplicacin de un
mtodo/responsabilidad que no retorna un valor), entonces tambin ser vlida la
operacin expA.met(exp1,...,expn) sin retornar ninguna expresin como resultado,
autodefinida anlogamente a la anterior (a menos que met no se encuentre definido
como mtodo/responsabilidad propio de la clase asociada al tipo heredado).
d) Si es vlida la expresin expB.met(exp1,...,expn) con expresiones-parmetros
exp1 a expn que son de tipo T1 a Tn respectivamente, que retorna una expresin de tipo T,
(aplicacin de un mtodo/responsabilidad que retorna un valor), entonces tambin ser
vlida la expresin expA.met(exp1,...,expn), tambin retornando una expresin de
Operacin de tuplas
Los campos de una tupla se comportan como si fueran atributos. Estos campos se utilizan
sobre una tupla para proyectar sus valores. O sea que vale lo siguiente:
Expresiones LET
Existe otro tipo de expresiones, muy utilizada para no repetir o simplificar evaluaciones. Son
las expresiones LET, que son expresiones con la siguiente sintaxis:
let var: T = exp1 in exp2
La evaluacin de esta expresin let consta de la evaluacin de la expresin exp2,
reemplazando antes todas las apariciones libres de la variable var (que dentro de exp2 es usada
como expresin) por la expresin exp1. El tipo de var (T) debe especificarse, y debe coincidir
con el tipo del la expresin exp1.
Dentro de la expresin exp2 se reconocen como expresiones a las vinculaciones a variables
reconocidas en el contexto de la expresin let, y a esta nueva variable var (que slo es local a
la expresin let).
Dentro de la expresin expT se puede utilizar la expresin self (hacer una referencia al
objeto recientemente creado), siempre y cuando de l se obtengan valores de atributos o
pseudoatributos, para los cuales su valor inicial haya sido especificado en una clusula init
anterior.
T1.OCLasType(T2: OCLType): T2
Retorna la misma expresin recibida (de tipo T1), aunque se asume que el tipo de esta
expresin retornada es de tipo T2. Representa el typecast elegante de la orientacin a objetos,
donde debe ocurrir que T2 < T1. El objetivo del uso de esta operacin es poder aplicar algn
atributo, pseudoatributo o mtodo/responsabilidad de un subtipo del tipo de la expresin si se
sabe con seguridad que tambin pertenece a ese subtipo.
Un ejemplo
Dado el siguiente diagrama de clases, se especificarn luego algunas restricciones y
definiciones con OCL:
Existen embarcaciones pesqueras. Cada una de ellas tiene un nombre, un largo y ancho (estos
dos ltimos en metros), donde no puede ser ms ancha que larga. Posee tambin un mximo
nmero de tripulantes, aunque su tripulacin es estable (siempre es tripulada por los mismos
marinos). Nunca la cantidad de tripulantes estables debe exceder a su cantidad mxima. Las
embarcaciones pueden tener un propietario, que no necesariamente es marino. Tanto los
marinos como los que no lo son, poseen un nombre, un apellido y un telfono. Los no marinos
poseen adems un nmero de fax, cuya caracterstica debe ser la misma que la de su nmero
de telfono.
Cada marino dentro de una embarcacin cumple un rol dentro de la misma, que puede ser
capitn, marinero o grumete. Dentro de una embarcacin slo puede haber exactamente un
capitn. A lo sumo, el 10% de la tripulacin de una embarcacin puede ser grumete.
Toda embarcacin debe estar inscripta en una asociacin de pesqueros. Cada asociacin se
compone de uno o ms socios, que son los nicos autorizados a formar parte de las
tripulaciones de barcos pesqueros inscriptos en la asociacin de la que son socios. Los no
marinos pueden obtener las asociaciones donde estn inscriptas las embarcaciones de su
propiedad.
Cada embarcacin puede realizar salidas de pesca en una fecha determinada, que no pueden
ser ms de dos por da. En ella, los integrantes de la tripulacin (que son los nicos que
pescan) pescan en forma independiente, y cada uno obtiene una cierta cantidad de kilos de
pescado. Esta cantidad de kilos de pescado por tripulante puede incrementarse, siempre y
cuando el peso total de pescado en la embarcacin no exceda los 1000 kilos. Se quiere conocer
tambin la cantidad de kilos de pescado en total para cada salida de pesca.
Invariantes:
Los propietarios no marinos poseen adems un nmero de fax, cuya caracterstica debe ser la
misma que la de su nmero de telfono.
context: Civil
inv: self.fax.caracteristica = self.telefono.caracteristica
(se asume que existe la propiedad caracteristica para las expresiones de tipo Telef)
Cada asociacin se compone de uno o ms socios, que son los nicos autorizados a formar
parte de las tripulaciones de barcos pesqueros inscriptos en la asociacin de la que son socios.
context: Embarcacion
inv: self.inscripta.socios->includesAll(self.tripulantes)
Cada embarcacin puede realizar salidas de pesca en una fecha determinada, que no pueden
ser ms de dos por da.
context: Pesca
inv: self.realizada.realiza->
select(s|s.fechaSalida = self.fechaSalida)->size() <= 2
Las embarcaciones donde pescan los pescadores debe ser la misma que la de ellos mismos
pensados como embarcados. (esta es una restriccin existente debido a la estructura del
diagrama de clases).
context: Salida
inv: self.pescoEn.realizada = self.pescadores.tripula
Definicin de responsabilidades:
Las pescas pueden incrementarse (siempre y cuando no excedan los 1000 kilos en la
embarcacin).
context: Pesca::incrPesca(p: Peso)
pre: self.pescoEn.pesoPesca + p <= 1000
post: self.pesoPesca = self.pesoPesca@pre + p
Bibliografa
- UML 2.0 OCL Specification (documento de la OMG publicado en Internet en
http://www.omg.org/docs/ptc/03-10-14.pdf).
- Object Constraint Language Specification (documento de Internet ubicado en
http://umlcenter.visual-paradigm.com/umlresources/obje_11.pdf).
- Muchos otros documentos extrados de Internet.