Object Constraint Language Philip Stephen Medcraft Sumário Introdução Ligação com a UML Tipos básicos e operações Objetos e propriedades Operações em coleções Introdução Modelos gráficos são completos? Podemos gerar especificações precisas apenas com modelos gráficos? Muitas vezes, sentimos a necessidade de adicionar restrições aos objetos. Uma linguagem natural pode resolver? Uma linguagem formal é mais precisa! Introdução OCL é uma linguagem descritiva. Uma expressão OCL não pode alterar nada no esquema. O estado do sistema nunca mudará devido a uma expressão OCL. Quando executada, uma expressão OCL simplesmente devolve um valor. Introdução A OCL pode ser usada com diferentes propósitos: Para especificar restrições em classes e tipos no diagrama de classes. Para descrever pré e pós condições para métodos. Como uma linguagem de navegação. Ligação com a UML Uma expressão OCL: ´Essa é uma expressão OCL’ O contexto para a expressão: NomeDoTipo ´Expressão OCL no contexto de NomeDoTipo’ Uma expressão OCL é escrita no contexto de uma instância de um tipo específico. Ligação com a UML Em uma expressão OCL, o nome self é usado para referenciar o contexto. Exemplo: Company self.numberOfEmployees Outra opção: c : Company c.numberOfEmployees Ligação com a UML Pré e Pós condições: A expressão é uma pré ou pós condição para uma operação. Portanto, a instância atual (contexto) é do tipo que possui a operação. Person::income(d : Date) : Integer post: result = ... Alguma função ... Tipos básicos e operações Boolean (and, or, not, implies, if-then-else) Integer (*, +, -, /, abs) Real (*, +, -, /, floor) String (toUpper, concat) Collection Set Bag Sequence Tipos básicos e operações Cada expressão OCL é escrita no contexto de um modelo UML contendo: um número de classes; associações entre as classes; generalizações. Todos as classes do modelo UML são tipos nas expressões OCL anexadas ao modelo. Tipos básicos e operações Relações entre tipos: Os tipos básicos são organizados numa hierarquia. Uma expressão OCL é válida quando os seus tipos conformam. Caso contrário, temos um “type conformance error”. Tipos básicos e operações Os relacionamentos entre os tipos devem obedecer as seguintes regras: Cada tipo conforma com seu supertipo; Se tipo1 conforma com tipo2, e tipo2 conforma com tipo3, então tipo1 conforma com tipo3. Tipos básicos e operações Casting: Algumas vezes precisamos usar uma propriedade de um objeto que é definido num subtipo do objeto corrente. object.oclAsType(Tipo2) Neste exemplo, object é do tipo Tipo1. Só podemos fazer o cast para um subtipo do tipo corrente. Objetos e propriedades Propriedades: O valor de uma propriedade de um objeto definido num diagrama de classes é especificado da seguinte forma: UmTipo self.nomePropriedade Objetos e propriedades Atributos A idade de uma pessoa é escrita como: Person self.age O tipo dessa expressão é o tipo do atributo age (Integer). Poderíamos definir como regra: Person self.age >= 0 Objetos e propriedades Operações Cada operação pode ser definida por uma restrição de pós-condição. Person::income (d : Date) : Integer post: result = -- alguma função -- Para o caso de uma operação sem parâmetros: Company self.stockPrice() Objetos e propriedades Navegação Partindo de um certo objeto, podemos navegar numa associação do diagrama de classes, para referenciar outros objetos e suas propriedades. Company self.manager -- do tipo Person self.employee-- do tipo Set(Person) Objetos e propriedades Navegação A execução da primeira expressão resultará num objeto do tipo Person. A execução da segunda expressão resultará num conjunto de Pessoas. Por default, navegação sempre resulta num conjunto. No caso da associação conter o elemento {ordered}, a navegação resulta numa sequência. Objetos e propriedades Os tipos Set, Bag e Sequence são prédefinidos em OCL. Cada um desses tipos de coleção possui um grande número de operações pré-definidas. Temos acesso a uma propriedade de uma coleção usando uma seta ‘->’, seguida do nome da propriedade. Objetos e propriedades A expressão abaixo resulta no número de empregadores da Pessoa self. Person self.employer->size A expressão abaixo resulta em ‘true’ caso o conjunto de empregadores é vazio. Person self.employer->isEmpty Objetos e propriedades Alguns exemplos de expressões OCL: self.wife->notEmpty implies self.wife.age >=18 and self.husband->notEmpty implies self.husband.age >= 18 self.employee->size <= 50 self.wife.sex = #female and self.husband.sex = #male not ((self.wife->size = 1) and (self.husband->size = 1)) Objetos e propriedades Navegação para classes de associação: OCL usa um ponto e o nome da classe de associação iniciando com letra minúscula. Person self.job Resulta no conjunto de todos os empregos que a pessoa possui dentre as empresas. Objetos e propriedades Navegação: Podemos ainda fazer uma melhor seleção dos objetos. Veja os exemplos: Bank self.customer -- resulta num Set(Person) contendo -- todos os clientes do banco. self.customer[8764423] -- resulta numa pessoa que possui número da conta igual a 8764423 Objetos e propriedades Coleções: O tipo coleção é pré-definido em OCL. Define um grande número de operações pré-definidas que possibilitam ao autor manipular coleções. Collection é um tipo abstrato, com os tipos concretos de coleções sendo: • Set, Sequence, e Bag. Objetos e propriedades Set É o conjunto matemático. Não contém elementos duplicados. Bag É como Set, mas pode conter elementos duplicados. Sequence É como Bag, com elementos ordenados. Objetos e propriedades Podemos obter coleções das seguintes maneiras: Definindo de forma direta: • Set {1, 2, 3, 5, 7, 11, 13, 17} • Sequence {1, 2, 3, 5, 7, 11, 13, 17} • Bag {1, 2, 3, 2, 1} Através de uma navegação: Company self.employee Operações em coleções: collection1->union(collection2) Operações em coleções Operação Select Muitas vezes queremos apenas um subconjunto de uma coleção. O Select é uma operação realizada sobre uma coleção, com a seguinte sintaxe: Company self.employee->select (age > 50) Company self.employee->select (p | p.age > 50) Company self.employee->select (p : Person | p.age > 50) Operações em coleções Operação Reject Idêntica ao Select, no entanto, o subconjunto que pegamos da coleção é composta pelos elementos que não satisfazem à expressão. As duas expressões abaixo são iguais: Collection->reject ( v : Tipo | expressão-booleana ) Collection->select ( v : Tipo | not (expressão-booleana) ) Operações em coleções Operação Collect Usamos a operação quando queremos especificar uma coleção a partir de uma outra, mas com diferentes objetos da coleção original. Company self.employee->collect (birthDate) self.employee->collect (person | person.birthDate) self.employee->collect (person:Person | person.birthDate) Operações em coleções Operação ForAll Muitas vezes uma restrição é comum para todos os elementos de uma coleção. ForAll resulta num boolean. Retornará true caso a restrição seja comum a todos. Company self.employee->forAll ( sobrenome = ‘Schiel’ ) Será true, caso todos os empregados da empresa tenham sobrenome “Schiel”. Operações em coleções Operação Exists Muitas vezes precisamos saber se há pelo menos um elemento de uma coleção para o qual uma certa restrição é válida. Company self.employee->exists ( sobrenome = ‘Schiel’ ) Será true, caso exista pelo menos um empregado da empresa com sobrenome “Schiel”. Operações em coleções Operação Iterate A sintaxe é a seguinte: collection->iterate ( elem : Tipo; acc : Tipo = <expressão> | expressão-com-elem-e-acc ) collection->collect ( x : T | x.propriedade ) é idêntico a: collection->iterate ( x : T; acc : T2 = Bag{} | acc->including(x.property) )