A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Métodos Formais em Engenharia de Software 3c

Apresentações semelhantes


Apresentação em tema: "Métodos Formais em Engenharia de Software 3c"— Transcrição da apresentação:

1 jpf@fe.up.pt www.fe.up.pt/~jpf
Métodos Formais em Engenharia de Software 3c. Especificação Baseada em Modelos em VDM++ (3ª parte) João Pascoal Faria

2 Índice Definição de consultas tirando partido de operadores sobre conjuntos Acesso ao conjunto de instâncias duma classe a partir duma variável estática * Integridade referencial ao remover objectos Acesso ao conjunto de instâncias duma classe a partir dum objecto raiz Mapeamentos (maps) Modelação de associações qualificadas Modelação de generalizações Herança de invariantes * Enfraquecimento de pré-condições e fortalecimento de pós-condições Herança múltipla Resumo de mapeamento de UML para VDM++

3 Definição de consultas tirando partido de operadores sobre conjuntos
Obter todos os ascendentes de uma pessoa: public GetAscendentes() res : set of Pessoa == return (if pai = nil then {} else {pai} union pai.GetAscendentes()) union (if mae = nil then {} else {mae} union mae.GetAscendentes()); Obter todos os descendentes de uma pessoa: public GetDescendentes() res : set of Pessoa == return GetFilhos() union dunion {f.GetDescendentes() | f in set GetFilhos()}; Obter todos os irmãos (e meios-irmãos) de uma pessoa: public GetIrmaos() res : set of Pessoa == return ((if pai = nil then {} else pai.GetFilhos()) union (if mae = nil then {} else mae.GetFilhos())) \ {self}; public GetDescendentes() res : set of Pessoa == ( dcl aux : set Of Pessoa := {}; dcl f : Pessoa; for f in set GetFilhos do aux := aux union {f} union f.GetDescendentes(); return aux ); ( dcl aux : set Of Pessoa := {}; dcl f : Pessoa; for f in set GetFilhos do aux := aux union {f} union f.GetDescendentes(); return aux ); Ver VDM/RegistoCivil_v2.zip

4 Acesso ao conjunto de instâncias duma classe a partir duma variável estática
A referência de uma pessoa para os seus filhos é redundante, pois estes podem obter-se a partir das referências (dos filhos) para o pai e a mãe Mas, para isso, precisamos de ter acesso ao conjunto de instâncias da classe Pessoa Limitação: Em VDM++ não existe acesso automático ao conjunto de instâncias de uma classe O mesmo se passa nas linguagens de programação OO convencionais Em bases de dados relacionais e em OCL temos acesso automaticamente ao conjunto de instâncias (em OCL com classe.allInstances) Uma solução possível é guardar o conjunto de instâncias duma classe numa variável estática que é actualizada pelos construtores (e destrutores ?)

5 Acesso ao conjunto de instâncias duma classe a partir duma variável estática
Pessoa - pessoas: set of Pessoa Em UML, sublinhado significa estático (static) + GetPessoas(): set of Pessoa + GetFilhos(): set of Pessoa

6 Acesso ao conjunto de instâncias duma classe a partir duma variável estática
class Pessoa instance variables … private static pessoas : set of Pessoa := { }; operations public Pessoa( … ) res : Pessoa == ( … ; pessoas := pessoas union {self}; … ) pre … ; public static GetPessoas() res : set of Pessoa == return pessoas; -- Ilustra como obter filhos a partir do conjunto de todas -- as instâncias e das referências para pai e mãe public GetFIlhos() res : set of Pessoa == return { f | f in set pessoas & f.GetPai() = self or f.GetMae() = self }; end Pessoa Construção de conjunto em compreensão Ver VDM/RegistoCivil_v2.zip

7 * Integridade referencial ao remover objectos
* - Saltar numa 1ª leitura! * Integridade referencial ao remover objectos Se existir uma operação para remover uma pessoa (do conjunto de pessoas registadas na variável estática “pessoas”), é preciso alguma cautela para preservar a integridade das várias referências entre objectos (integridade referencial) Problema semelhante coloca-se em bases de dados relacionais, com restrições de integridade referencial (foreign key constraints) Nota: Em VDM++, não existe uma operação para eliminar explicitamente um objecto, o que podemos fazer é deixar de o referenciar ou removê-lo de um conjunto (de referências) O objecto existe enquanto for referenciado O mesmo se passa nas linguagens de programação OO de alto nível, como Java e C# (mas não C++ e na linguagem de acções de UML) Se por um lado isto é útil, por outro lado pode causar problemas, pois o objecto pode continuar a ser usado por quem tenha mantido uma referência para ele Mas é melhor esquecer este problema de “baixo nível” …

8 * Integridade referencial ao remover objectos
Conceptualmente, a integridade referencial que queremos preservar ao remover pessoas (e não só) pode ser expressa pelo seguinte invariante: -- o conjunto de pessoas deve ser fechado pelas associações -- pai/mae/conjuge/exConjuges inv forall p in set pessoas & (p.pai <> nil => p.pai in set pessoas) and (p.mae <> nil => p.mae in set pessoas) and (p.conjuge <> nil => p.conjuge in set pessoas) and (elems p.exConjuges subset pessoas); Recomendação: esquecer este invariante de “baixo nível”, pois tem a ver com questões de “codificação” e não com o domínio do problema

9 * Integridade referencial ao remover objectos
Algumas opções sobre como preservar a integridade referencial: Impedir a remoção se existirem objectos que referenciam o objecto a remover Formalizado por pré-condição Corresponde a “on delete restrict” em BDRs Pode ser demasiado restritivo, mas é o comportamento por defeito mais seguro Anular de alguma forma as referências para o objecto, antes de o remover Corresponde a “on delete set null” em BDRs Só é possível com associações para 0 ou 1, ou 0 ou mais Se for possível, é geralmente a melhor opção Eliminar os objectos que referenciam o objecto a remover, antes de o remover Corresponde a “on delete cascade” em BDRs Pode ser demasiado desastroso Soluções mistas, específicas do domínio em causa

10 * Integridade referencial ao remover objectos
Exemplo da 1ª opção na classe Pessoa public Remover() == pessoas := pessoas \ {self} pre not exists p in set pessoas & p.pai = self or p.mae = self or p.conjuge = self or self in set elems p.exConjuges; Exemplo da 2ª opção na classe Pessoa public Remover() == ( for all p in set pessoas do if p.pai = self then p.SetPai(nil); if p.mae = self then p.SetMae(nil); if p.conjuge = self then p.SetConjuge(nil); if self in set elems p.exConjuges then p.RemoveExConjuge(self) ); pessoas := pessoas \ {self} ); Operações auxiliares a definir (não se pode fazer obj_ref.inst_var := valor) instrução “for all”, não confundir com expressão “forall”

11 Acesso ao conjunto de instâncias duma classe a partir dum objecto raiz
Outra solução para ter acesso ao conjunto de instâncias de uma classe, e que escala para o caso de várias classes, é ter um “objecto raiz” a partir do qual se pode navegar para os restantes objectos do sistema (de uma ou mais classes) Na maioria dos sistemas acabamos por precisar de um objecto raiz para guardar alguns dados gerais Exemplo numa biblioteca: classe Biblioteca com referências para Publicação, Sócio e Empréstimo (tratado nas aulas práticas) Exemplo no sistema de registo civil: ver a seguir

12 Acesso ao conjunto de instâncias duma classe a partir dum objecto raiz
classe só com uma instância (singleton) (o objecto raiz do sistema) RegistoCivil 1 + RegistaPessoa(p: Pessoa) + GetPessoas(): set of Pessoa + GetFilhos(p: Pessoa): set of Pessoa Todas as pessoas estão registadas 1 navegação do objecto raiz para as instâncias de Pessoa * -pessoas Pessoa

13 Acesso ao conjunto de instâncias duma classe a partir dum objecto raiz
class RegistoCivil instance variables private pessoas : set of Pessoa := { }; operations public RegistaPessoa(p : Pessoa) == pessoas := pessoas union {p} pre not p in set pessoas; public GetPessoas() res : set of Pessoa == return pessoas; public GetFIlhos(p: Pessoa) res : set of Pessoa == return { f | f in set pessoas & f.GetPai() = p or f.GetMae() = p } pre p in set pessoas; end RegistoCivil regista uma instância de Pessoa previamente criada

14 * Acesso ao conjunto de instâncias duma classe a partir dum objecto raiz
O modelo anterior em VDM++ não garante duas restrições do modelo UML: Podem existir instâncias de “Pessoa” que não estão registadas em “RegistoCivil” (violando multiplicidade 1 num dos extremos da associação) (2) Podem existir múltiplas instâncias de “RegistoCivil” (violando multiplicidade 1 da classe) Em consequência disso, uma pessoa registada em “RegistoCivil” pode ter pessoas relacionadas (pai, mãe, cônjuge, ex-conjuges) que não estão registadas ou estão registadas numa instância diferente de “RegistoCivil” É o mesmo problema de integridade referencial que já apareceu na solução com uma variável estática, ao introduzir a operação de remover pessoa Em consequência disso, por exemplo “GetFilhos” só dá efectivamente os filhos registados na mesma instância de “RegistoCivil” Abordagem recomendada: ignorar estas questões de “codificação”, e pressupor que o modelo é “bem utilizado” No arranque do sistema, deve-se criar uma instância única de “RegistoCivil” Cada nova instância de “Pessoa” deve ser imediatamente registada em “RegistoCivil”

15 * Acesso ao conjunto de instâncias duma classe a partir dum objecto raiz
Se fizermos questão (não recomendado), podemos impor (de forma pouco declarativa) as multiplicidades indicadas no diagrama UML Para garantir que a classe “RegistoCivil” tem exactamente uma instância (padrão singleton, class RegistoCivil instance variables private static uniqueInstance : RegistoCivil := new RegistoCivil(); operations -- construtor privado, para impedir criação de objectos fora da classe private RegistoCivil() res: RegistoCivil == return self; -- acesso público à única instância da classe (criada internamente) public static GetUniqueInstance() res: RegistoCivil == return uniqueInstance; end RegistoCivil

16 * Acesso ao conjunto de instâncias duma classe a partir dum objecto raiz
Para garantir que todas as instâncias de Pessoa estão associadas à única instância de RegistoCivil: class Pessoa operations public Pessoa(…) … ( …; RegistoCivil`GetUniqueInstance().RegistaPessoa(self); … ) pre …; end Pessoa Também podemos passar a operação GetFilhos para a classe Pessoa: class Pessoa operations public GetFilhos() res : set of Pessoa == return { f | f in set RegistoCivil`GetUniqueInstance().GetPessoas() & f.GetPai() = self or f.GetMae() = self } end Pessoa Ver VDM/RegistoCivil_v3.zip

17 Mapeamentos (maps) Um mapeamento (map) é uma função finita definida em extensão Faz corresponder a cada elemento (chave) de um conjunto A, ou de um subconjunto de A, um elemento (valor) doutro conjunto B Sintaxe: map A to B ou inmap A to B (mapeamento injectivo) A e B são tipos de dados quaisquer Cada elemento de um mapeamento é designado maplet e representa-se em ASCII na forma chave |-> valor Domínio: Conjunto de elementos de A que têm um valor correspondente em B Contra-domínio (range): Conjunto de elementos de B que correspondem a alguma chave de A

18 Mapeamentos (maps) Construtores:
Por enumeração: {a1 |-> b1, a2 |-> b2, ..., an |-> bn} Constructs a mapping of the enumerated maplets. The empty map will be written as {|->}. Em compreensão: {ed |-> er | bd1, ..., bdn & P} constructs a mapping by evaluating the expressions ed and er on all the possible bindings for which the predicate P evaluates to true bd1, ..., bdn are bindings of free identifiers from the expressions ed and er to sets or types

19 Mapeamentos (maps) (fonte: langmanpp_a4.pdf)

20 Mapeamentos (maps)

21 Mapeamentos (maps)

22 Mapeamentos (maps)

23 Mapeamentos (maps)

24 Mapeamentos (maps)

25 Mapeamentos (maps)

26 Modelação de associações qualificadas
RegistoCivil 1 + RegistaPessoa(p: Pessoa, bi: nat) + ProcuraPessoa(bi: nat) : [Pessoa] + RegistaPessoa(p: Pessoa, bi: nat) + GetPessoa(bi: nat) : [Pessoa] bi : nat Qualificador: atributo(s) usado(s) para navegar de “RegistoCivil” para Pessoa (chave de navegação) 1 A cada número de bi corresponde 0 (no caso de nº não atribuído) ou 1 pessoa 0..1 - pessoas Associação qualificada Pessoa

27 Modelação de associações qualificadas
Associações qualificadas são modeladas através de mapeamentos (map) ou mapeamentos injectivos (inmap), conforme a multiplicidade class RegistoCivil types public BI = nat; instance variables private pessoas : inmap BI to Pessoa := { |-> } ; operations public RegistaPessoa(bi: BI, p : Pessoa) == pessoas := pessoas munion { bi |-> p } pre not bi in set dom pessoas and not p in set rng pessoas ; public GetPessoa(bi: BI) res : [Pessoa] == return if bi in set dom pessoas then pessoas(bi) else nil; end RegistoCivil mapeamento vazio Ver VDM/RegistoCivil_v4.zip

28 Modelação de generalizações
Pessoa # sexo : Sexo Homem Mulher {sexo = <Masculino>} {sexo = <Feminino>} class Pessoa instance variables protected sexo : Sexo; end Pessoa class Homem is subclass of Pessoa inv sexo = <Masculino> ; end Homem class Mulher is subclass of Pessoa inv sexo = <Feminino> ; end Homem

29 Herança de invariantes
A subclasse herda os invariantes da super-classe, podendo acrescentar outros (fortalecendo o conjunto de invariantes) class Homem is subclass of Pessoa inv sexo = <Masculino> ; end Homem

30 * Enfraquecimento de pré-condições e fortalecimento de pós-condições
Ao redefinir uma operação herdada da superclasse, não se deve violar o contracto (pré-condição e pós-condição) estabelecido na super-classe A pré-condição pode ser enfraquecida (relaxada) na subclasse, mas não fortalecida (não pode ser mais restritiva) qualquer chamada que se prometia ser válida na pré-condição da superclasse, deve continuar a ser aceite na pré-condição da subclasse pre_op_superclass => pre_op_subclass A pós-condição pode ser fortalecida na subclasse, mas não enfraquecida a operação na subclasse deve continuar a garantir os efeitos prometidos na superclasse, podendo acrescentar outros efeitos post_op_subclass => post_op_superclass

31 * Enfraquecimento de pré-condições e fortalecimento de pós-condições
class Figura types public Ponto :: x : real y : real; instance variables protected centro : Ponto; operations public Resize(factor: real) == is subclass responsibility pre factor > post centro = centro~; end Figura class Circulo is subclass of Figura instance variables private raio : real; inv raio > 0; operations public Circulo(c: Ponto, r: real) res:Circulo == ( raio := r; centro := c; return self ) pre r > 0; public Resize(factor: real) == raio := raio * abs(factor) pre factor <> post centro = centro~ and raio = raio~ * abs(factor); end Circulo abstracta pre_Figura`Resize(…) post_Figura`Resize(…) pre_Circulo`Resize(…) post_Circulo`Resize(…)

32 TrabalhadorEstudante
Herança múltipla Em VDM++, uma classe pode herdar (ser subclasse) de mais do que uma superclasse Pessoa Trabalhador Estudante TrabalhadorEstudante class TrabalhadorEstudante is subclass of Trabalhador, Estudante end TrabalhadorEstudante

33 Resumo de mapeamento de UML para VDM++
C2 r5 r3 C5 C1 C3 * q : Q 1 r4 r6 r7 C4 C6 {ordered} 0..1 0..1 * C7 class C1 is subclass of C2 instance variables r3 : C3; r4 : [C4]; r5 : set of C5; r6 : seq of C6; r7 : map Q to C7; end C1 seq1 se for para 1..* inmap se for de 0..1

34 Referências e leituras adicionais
Manual de VDM++ (langmanpp_a4.pdf) Manual de VDMTools (usermanpp_a4.pdf) Modelling Systems: Practical Tools and Techniques in Software Development, John Fitzgerald and Peter Gorm Larsen, Cambridge University Press, 1998.  (existe na biblioteca da FEUP) Validated Designs for Object-oriented Systems. John Fitzgerald, Peter Gorm Larsen, Paul Mukherjee, Nico Plat and Marcel Verhoef. ISBN: Springer Verlag, New York Specification of Software Systems, V.S. Alagar and K. Periyasamy, ISBN: , Springer, 1998.


Carregar ppt "Métodos Formais em Engenharia de Software 3c"

Apresentações semelhantes


Anúncios Google