Capítulo 8: Object Constraint Language
Agenda • • • • • •
OCL Predicados Simples Precondiciones Poscondiciones Contratos Sets, Bags y Sequences
OCL: Object Constraint Language • Lenguaje formal para expresar constraints sobre un conjunto de objetos y sus atributos en un modelo • Usado para escribir constraints que no pueden ser expresados en un diagrama
• Desarrollado por IBM • Originalmente parte del estándar UML
• Declarativo • Basado en Conjuntos y Multiconjuntos.
Contrato • Contrato: Un acuerdo legal entre dos partes en el cual ambas partes aceptan obligaciones y aceptan sus derechos • Una violación de contrato usualmente conlleva a una compensación en dinero de la parte afectada
• Contrato OO: Describe los servicios que son provistos por un objeto si ciertas condiciones son satisfechas • servicios = “obligaciones”, condiciones = “derechos” • Una violación del contrato OO es manejada por una excepción.
Contrato OO • Un contrato OO describe los servicios que son provistos por un objeto. Para cada servicio, se describe específicamente: • Las condiciones bajo las cuales el servicio será provisto • Una especificación del resultado del servicio que es provisto.
• Ejemplos: • Una carta recibida después de 18:00 será entregada al próximo día hábil a cualquier dirección en Alemania. • Por el precio de 4 Euros una carta con un peso máximo de 80 gramos será entregada en cualquier lugar de Alemania dentro de las 4 horas de haberla recibido.
Modelación de Contratos OO • Lenguaje Natural • Notación Matemática • Modelos y contratos: • Un lenguaje para la formulación de constraints con la formalidad de una notación matemática y la facilidad del lenguaje natural: UML + OCL (Object Constraint Language) • Usa las abstracciones del modelo UML • OCL está basado en Cálculo de Predicado
Contratos y Especificación Formal
• Contratos permiten al caller y al provider compartir las mismas suposiciones sobre la clase • Un contrato incluye 3 tipos de constraints: • Invariante: • Un predicado que siempre es verdad para todas las instancias de una clase • Precondición (“derechos”): • Debe ser verdad antes que una operación sea invocada • Poscondición (“obligación”): • Debe ser verdad después que una operación es invocada.
• Un contrato es llamado una especificación formal, si los invariantes, derechos y obligaciones en el contracto no son ambiguos.
Conceptos Básicos - OCL • Expresiones OCL • Devuelven True o False • Son evaluadas en un contexto especifico: una clase o una operación • Los constraints aplican a todas las instancias.
Predicados Simples en OCL Ejemplo: context Tournament inv: self.getMaxNumPlayers() > 0 En Español: “El número máximo de jugadores en cualquier torneo debe ser un número positivo.”
Notas: • “self” denota todas las instancias de “Tournament” • OCL usa la misma notación de punto como Java.
Precondiciones en OCL Ejemplo: context Tournament::acceptPlayer(p) pre: not self.isPlayerAccepted(p) En Español: “La operación acceptPlayer(p) puede ser solo invocada si el jugador p no ha sido aún aceptado en el torneo.”
Notas: • El contexto de una precondición es una operación • isPlayerAccepted(p) es una operación definida por la clase Tournament.
Poscondiciones en OCL Ejemplo: context Tournament::acceptPlayer(p) post: self.getNumPlayers() =
[email protected]() + 1 En Español: “El número de jugadores aceptados en un torneo se incrementa en uno después de completar acceptPlayer()”
Notas: • self@pre denota el estado del torneo antes de la invocación de la operación. • Self denota el estado del torneo después de completar la operación.
Contrato OCL para acceptPlayer() en Tournament context Tournament::acceptPlayer(p) pre: not self.isPlayerAccepted(p) context Tournament::acceptPlayer(p) pre: self.getNumPlayers() < self.getMaxNumPlayers() context Tournament::acceptPlayer(p) post: self.isPlayerAccepted(p) context Tournament::acceptPlayer(p) post: self.getNumPlayers() =
[email protected]() + 1
Contrato OCL para removePlayer() en Tournament context Tournament::removePlayer(p) pre: self.isPlayerAccepted(p) context Tournament::removePlayer(p) post: not self.isPlayerAccepted(p) context Tournament::removePlayer(p) post: self.getNumPlayers() =
[email protected]() - 1
Implementación en Java de la clase Tournament (Contrato como un conjunto de comentarios en JavaDoc) public class Tournament { /** The maximum number of players * is positive at all times. * @invariant maxNumPlayers > 0 */ private int maxNumPlayers; /** The players List contains * references to Players who are * are registered with the * Tournament. */ private List players; /** Returns the current number of * players in the tournament. */ public int getNumPlayers() {…} /** Returns the maximum number of * players in the tournament. */ public int getMaxNumPlayers() {…}
/** The acceptPlayer() operation * assumes that the specified * player has not been accepted * in the Tournament yet. * @pre !isPlayerAccepted(p) * @pre getNumPlayers()includes(p)
Tournament +start:Date +end:Date +acceptPlayer(p:Player) * tournaments
players *
* players Player +name:String +email:String
Colección en OCL • La Colección de tipo OCL es la superclase genérica de una colección de objetos de Tipo T • Las Subclases de Colección son • Set: Conjunto en el sentido matemático. Cada elemento puede aparecer solamente una vez • Bag: Una colección, en la cual los elementos pueden aparecer mas de una vez (también llamada multiset) • Sequence: Un multiset, en el cual los elementos están ordenados
• Ejemplo de Colecciones: • Set(Integer): un conjunto de números enteros • Bag(Person): un multiconjunto de personas • Sequence(Customer): una secuencia de clientes
Sets, Bags y Sequences • Sets, Bags y Sequences están predefinidos en OCL y son subtipos de Collection. OCL ofrece un gran número de operaciones predefinidos sobre colecciones. Ellos tienen la forma: collection->operation(arguments)
Operaciones para OCL-Collections (1) size: Integer
Número de elementos en la colección
includes(o:OclAny): Boolean
True, si el elemento o está en la colección
count(o:OclAny): Integer
Cuenta cuántas veces un elemento está contenido en la colección
isEmpty: Boolean
True, si la colección está vacía
notEmpty: Boolean True, si la colección no está vacía El tipo OclAny es el Tipo OCL mas general.
Operaciones para OCL-Collections(2) union(c1:Collection) Unión con la colección c1
intersection(c2:Collection) Intersección con la colección c2
select(expr:OclExpression)
Subconjunto de todos los elementos de la colección, que satisface la expresión expr.
Navegación a través de una Asociación 1:N (Navegación clase directamente relacionada ) Ejemplo: Un Cliente no debe tener mas de 4 tarjetas context Customer inv: card->size() size() = 0 }
earn(i: Integer) i >= 0
burn(i: Integer)
isEmpty(): Boolean
points >= i and i >= 0
precondición de operación points = points@pre + i
result = (points=0)
points = points@pre - i
poscondición de operación
Navegación a través de una Asociación Restringida • Navegación a través de una asociación con el constraint {ordered} produce una secuencia • Ejemplo: El número de niveles de servicio debe ser 2 LoyaltyProgram servicelevel->size() = 2 LoyaltyProgram enroll(k: Customer)
servicelevel denota una secuencia
{ordered} * ServiceLevel name: String
Operaciones sobre Sequence first: T
El primer elemento de una secuencia
last: T
El último elemento de una secuencia
at(index:Integer): T
Elemento en el index de la secuencia
Ejemplo: El primer nivel en el loyalty program tiene el nombre de 'Silver„. El nivel mas alto es „Platinum'.“ OCL-Invariants: LoyaltyProgram: servicelevel->first().name = "Silver“ LoyaltyProgram: servicelevel->last().name = “Platinum“
LoyaltyProgram enroll(c:Customer)
1 {ordered} 1..* ServiceLevel name: String
Navegación a través de distintas Asociaciones 1:N LoyaltyProgram programs
1..* enroll(k: Customer)
Customer name:String titel: String age: Integer .* Dateof Birth:Date age(): Integer
*
1..* ProgramPartner
nrcustomer:
Integer
Ejemplo: “El número de clientes registrados por un program partner debe ser igual al número de clientes pertenecientes a un loyalty program ofrecido por el program partner” Context ProgramPartner inv nrcustomer = loyaltyprogram->customer->size() loyaltyprogram denota un conjunto de objetos de tipo LoyaltyProgram
customer denota un multiconjunto de objetos de tipo Customer
ProgramPartner nrcustomer = loyaltyprogram->customer->size()
Conversión entre Colecciones • OCL ofrece operaciones para convertir Colecciones: asSet
Transforma un multiset o sequence a set
asBag
Transforma un set o sequence a multiset
asSequence
Transforma un set o multiset a sequence.
Ejemplo de una Conversión programPartner nrcustomer = loyaltyprogram->customer->size() Cuidado: Esta expresión puede contener un cliente especifico varias veces! El número de clientes distintos puede obtenerse como:
programPartner nrcustomer = loyaltyprogram->customer->asSet()>size() LoyaltyProgram
programs
1..* entroll(k: Customer)
1..* programPartner
nrcustomer:
Integer
*
Customer name:String titel: String age: Integer .* dateOfBirth:Date age(): Integer
Evaluando Expresiones OCL cuando se navega un Diagrama de Clases • Navegación de una asociación con multiplicidad 1 • Resultado: un solo objeto
• Navegación de una asociación con multiplicidad 0..1 • Conjunto vacío, si no hay objetos, c.c. un solo objeto
• Navegación de una asociación con multiplicidad n • Resultado: Una colección de objetos • Si la asociación está {ordered}, el resultado de la navegación es una secuencia OCL • Múltiples asociaciones “1-n” puede resultar en un multiset (bag) • C.C. el resultado es un set.
Especificación Formal de los Constraints en OCL
1.
2.
“Una persona puede tener una hipoteca solo sobre la casa que le pertenece” context Mortgage inv: security.owner = borrower “La fecha de inicio de una hipoteca debe ser antes de su fecha de finalización.” context Mortgage inv: startDate < endDate
Calculo de Predicado vs Lógica de Primer-Orden • OCL está basado en lógica proposicional • La lógica proposicional consiste de formulas bien formadas (fbf) construidas de un conjunto símbolos primitivos (true, false), letras (a, b, x,y,...), y un conjunto de operadores (and ∧ , or ∨, not ∼ ...)
• OCL está basado una lógica de primer orden sobre el dominio de colecciones OCL • La lógica de primer orden también soporta cuantificación
• Existencial (en lógica simbólica: ∃, en OCL: exists) • El operador exists toma una expresión Booleana como parámetro. Evalúa a true si el parámetro es true para al menos un elemento de la colección
• Universal (en lógica simbólica:∀, en OCL: forAll) • El operador forAll toma una expresión Booleana como parámetro. Evalúa a true si es true para todos los elementos de la colección.
ForAll Player
players * Match -start:Date -end:Date
Tournament
+start:Date +end:Date players * +acceptPlayer(p:Player) tournaments *
matches *
Date now: Date
isBefore(t:Date): Boolean isAfter(t:Date): Boolean equals(t:Date): Boolean
Ejemplo: “Todos los Matches en un Tournament deben ocurrir dentro del período del Tournament” context Tournament inv: matches->forAll(m| m.start.isAfter(self.start) and m.start.isBefore(self.end))
ForAll (2) Player
players * Match -start:Date -end:Date
Tournament
+start:Date +end:Date players * +acceptPlayer(p:Player) tournaments *
matches *
“Un match puede solo involucrar jugadores que están aceptados en el Torneo” context Match inv: players->forAll(p| p.tournaments->exists(t| t.matches->includes(self)))
Exists Player
players * Match -start:Date -end:Date
Tournament
+start:Date +end:Date players * +acceptPlayer(p:Player) tournaments *
matches *
Date now: Date
isBefore(t:Date): Boolean isAfter(t:Date): Boolean =(t:Date): Boolean
Ejemplo: “Cada Tournament tiene al menos un Match en el primer día del Torneo” context Tournament inv: matches->exists(m:Match| m.start.equals(start))
Resumen • Constraints son predicados (frecuentemente expresiones Booleanas) sobre elementos del modelo UML • OCL es el ejemplo de un lenguaje formal que permite expresar constraints sobre modelos UML • constraints mas complejos que incluyen mas de una clase, atributo u operación puede ser formulado usando los 3 tipos de navegación básica: • Navegación atributo Local, clase directamente relacionada, clase indirectamente relacionada.
Lecturas Adicionales y Herramientas • J.B. Warmer, A.G. Kleppe • The Object Constraint Language: Getting your Models ready for MDA, Addison-Wesley, 2nd edition, 2003
• The Dresden OCL Toolkit • http://dresden-ocl.sourceforge.net/
• The Dresden OCL Toolkit for Eclipse • http://sourceforge.net/projects/dresdenocl/files/dresden-ocl2-for-eclipse/2.0/ocl2-for-eclipse2.0.tar.gz/download
Lecturas Adicionales • B. Meyer Object-Oriented Software Construction, 2nd edition, Prentice Hall, 1997.
• B. Meyer, Design by Contract: The Lesson of Ariane, Computer, IEEE, Vol. 30, No. 2, pp. 129-130, January 1997.
http://archive.eiffel.com/doc/manuals/technology/contract/arian e/page.html
• C. A. R. Hoare, An axiomatic basis for computer programming. Communications of the ACM, 12(10):576-585, October 1969. (Good starting point for Hoare logic: http://en.wikipedia.org/wiki/Hoare_logic)