• Nenhum resultado encontrado

Outra maneira de melhorar a especificação de um diagrama de classes é a inclusão de  invariantes. Invariantes são expressões booleanas que determinam uma condição que precisa ser  verdadeira em todos os estados consistentes do sistema para todas as instâncias de seu contexto. No  exemplo a seguir, criamos uma restrição que afirma que o número de amoras em uma cesta deve ser  sempre   menor   ou   igual   à   sua   capacidade.   Nomear   invariantes   é   opcional,   mas   pode   ser  extremamente útil, por exemplo, na validação automática de modelos, onde é importante que se  possa ter uma forma simples de referenciar as invariantes violadas. 

context Cesta

inv maximoDeAmorasNaCesta: nºDeAmoras <= capacidade 2.3.2.5. Pré­condições e pós­condições

Pré­condições   e   pós­condições   em   operações   são   maneiras   de   definir   precisamente   a  interface de um sistema, pois elas não especificam como a operação é implementada. Uma pré­

condição é uma expressão booleana que precisa ser verdadeira no momento em que a operação  inicia sua execução. Já uma pós­condição é uma expressão booleana que precisa ser verdadeira no  momento em que a operação termina sua execução. O seguinte exemplo mostra a utilização de  pré/pós­condições na operação Colheita::adicionarCestas(c : Cesta), onde a pré­condição especifica  que não interessam cestas com capacidade menor que 20 e a pós­condição especifica que a nova  cesta deve estar relacionada com a colheita:

context Colheita::adicionarCestas(c : Cesta) pre: c.capacidade >= 20

post: self.utiliza = self.utiliza@pre­>including(c)

O operador @pre é utilizado concatenando­se o mesmo ao nome do atributo/relação, para 

obter o valor que o atributo/relação possuía no momento de início da operação. 

2.3.2.6. Mensagens em pós­condições

Um aspecto muito útil em pós­condições é o fato de que elas podem indicar, pelo envio de  mensagens, que uma certa operação foi chamada. Por exemplo, quando o número total de amoras  colhidas for 300, pode­se chamar a função alertar() em todas as pessoas relacionadas á colheita,  para avisar que já foram colhidas amoras suficientes.

context Pessoa::colherAmora(a : Amora)

post: if totalDeAmoras >= 300 then self.colheita.emprega­>forAll(p : Pessoa | p^alertar())         else true endif

2.3.2.7. Definição de classes derivadas

Uma visão é um conceito bem conhecido em sistemas relacionais de banco de dados. O  conceito de classes derivadas, em modelagem UML/OCL, é um conceito similar ao conceito de  visão. Uma classe derivada é uma classe cujas propriedades podem ser completamente derivadas de  classes existentes. 

2.3.2.8. Multiplicidade dinâmica

Associações em diagramas de classe podem ser especificações imprecisas do sistema. Esse é  o caso quando a multiplicidade de uma associação não é fixada, mas deveria ser determinada de  acordo com outro valor no sistema. Isso é chamado de multiplicidade dinâmica. Um exemplo ocorre  no modelo da colheita de amoras onde uma associação entre as classes Colheita e Amora, indicando  que um certo número de amoras são colhidas, tem multiplicidade muitos (1..*) no lado da classe  Amora. Isso significa que o número cardinal máximo de amoras é ilimitado, porém o número  cardinal de amoras é limitado pelo número cardinal resultante da soma das capacidades das cestas  relacionadas com a colheita. Essa restrição não pode ser expressa no diagrama. Uma forma de  especificar essa cardinalidade é adicionar a seguinte restrição OCL ao modelo:

context Colheita

inv maximoDeAmoras: obtém­>size() <= utiliza­>collect(capacidade)­>sum() 2.3.2.9 Multiplicidade opcional

Uma multiplicidade opcional de uma associação em um diagrama de classes é, geralmente, 

uma especificação parcial do que é realmente intencionado. Nesses casos, uma associação opcional 

não é realmente livre e sua presença depende do estado de outros objetos. Em geral, quando há uma 

multiplicidade opcional em um diagrama de classes, deve­se utilizar invariantes OCL para descrever 

precisamente em que circunstâncias a associação opcional pode ser vazia ou não.

2.3.2.10. Restrições ou

Um   diagrama   de   classes   pode   conter   uma   restrição  ou  entre   duas   associações,  como  mostrado no exemplo da figura 20. Essa restrição significa que somente uma das associações  potenciais pode ser instanciada em um instante de tempo para qualquer objeto. Essa restrição é  representada no diagrama como uma seta tracejada conectando duas ou mais associações (que  possuam ao menos uma classe em comum) com a string {or} rotulando a linha. A multiplicidade  das associações precisa ser opcional, senão elas não poderão ser vazias.

No exemplo da colheita de amoras, supõe­se que uma pessoa possa participar da colheita  sendo  ou  proprietário de um número qualquer de colheitas  ou  funcionário de de um número  qualquer   de   colheitas.   Também   é   suposto   que   uma   colheita   possa   ter   qualquer   número   de  proprietários  (exemplos de colheitas  sem  proprietários poderiam ser  os  kibutzim  de  Israel,  há  algumas gerações)  e  que uma colheita possa ter qualquer número de funcionários. A escolha de  interpretação   parece   óbvia,   mas   como   todas   as   associação   têm   multiplicidade   opcional,   uma  transformação automática MDA poderia interpretar o modelo de outra forma, inter­substituindo os  operadores lógicos grifados nas frases anteriores.

Especificar a restrição ou visual como uma restrição OCL resolve a ambigüidade. Quando  desejar­se a primeira interpretação, deve­se anexar a seguinte invariante ao diagrama:

context Pessoa

inv: self.proprietário­>isEmpty() or self.trabalha­>isEmpty() A invariante para a segunda interpretação é:

context Colheita

inv: self.pertence­>isEmpty() or self.emprega­>isEmpty()

    

2.3.3. Estilos de modelagem

Além de servir para complementar a linguagem UML na escrita de restrições e consultas, a  linguagem   OCL   também   pode   ser   utilizada   para   expressar   informações   iguais   de   maneiras  diferentes. Há vários estilos de modelagem e nessa seção serão explicados alguns deles.

2.3.3.1. Definição de atributos ou operações

Atributos e operações podem ser definidos em um diagrama de classes adicionando­se os 

mesmos a um tipo. Mas eles também podem ser definidos por uma expressão OCL, não sendo 

necessário mostrá­los no diagrama. No exemplo a seguir, criou­se o atributo capacidadeRestante e a 

operação pararColheita:

context Cesta

def: capacidadeRestante : Integer = self.capacidade – self.nºDeAmoras context Colheita

def: pararColheita() : Boolean = if totalDeAmoras >= 300 then true else false endif

A expressão após o sinal de igual, em uma definição de atributo, é uma regra de derivação e  indica como o valor do atributo será calculado. Em uma definição de operação, a expressão que  segue o sinal de igual especifica o resultado da operação.

2.3.3.2. A restrição de subconjunto

Um diagrama de classe pode conter restrições de subconjunto, como mostrado na figura 20. 

Elas são representadas por setas tracejadas que vão do subconjunto ao conjunto e que possuem a  string {subset} rotulando as mesmas. Esse tipo de restrição informa que o conjunto de links de uma  associação é um subconjunto do conjunto de links de outra associação.

Mostrar todas restrições de subconjunto no diagrama pode torná­lo difícil de ler. Nesse caso,  pode­se especificar essas restrições utilizando expressões OCL. As duas restrições de subconjunto  mostradas no modelo de colheita poderiam ser expressas em OCL da seguinte maneira:

context Pessoa

inv: self.participa­>includesAll(self.proprietário) inv: self.participa­>includesAll(self.trabalha) context Colheita

inv: self.equipe­>includesAll(self.pertence) inv: self.equipe­>includesAll(self.emprega) 2.3.3.3. Herança X Invariantes

Novamente será referido o modelo de colheita de amoras, mais precisamente a associação  entre Amora e Cesta. Essa associação é especializada nas associações entre os subtipos AmoraVerde  e CestaTipo1 e AmoraMadura e CestaTipo2, que impõem que instâncias de AmoraVerde só podem  ser   armazenadas   em   instâncias   de   CestaTipo1   e   instâncias   de   AmoraMadura   só   podem   ser  armazenadas em instâncias de CestaTipo2. Essas associações entre os subtipos de Amora e Cesta  podem ser vistas como restrições à associação entre Amora e Cesta. Essas restrições podem ser  escritas em OCL para diminuir a complexidade do diagrama. No modelo, poderia­se retirar as sub­

associações do diagrama e adicionar as seguintes invariantes:

context AmoraVerde

inv: self.contida­>forAll(c : Cesta | c.oclIsKindOf(CestaTipo1)) context AmoraMadura

inv: self.contida­>forAll(c : Cesta | c.oclIsKindOf(CestaTipo2))

Assim cria­se um diagrama de mais fácil leitura, mas com a mesma expressividade. Porém,  se a única razão para a existência das subclasses de Cesta for diferenciar os tipos de cesta para os  diferentes   tipos   de   amoras,     poderia­se   excluir   as   subclasses   de   Cesta   e   criar   um  DataType  TipoCesta   que   as   especificasse,   colocando­se   um   atributo   tipo:TipoCesta   na   classe   Cesta   e  adicionando­se as seguintes invariantes:

context AmoraVerde

inv: self.contida­>forAll(c : Cesta | c.tipo = TipoCesta::tipo1)) context AmoraMadura

inv: self.contida­>forAll(c : Cesta | c.tipo = TipoCesta::tipo2))

Também poderia­se excluir as subclasses de Amora e criar um  DataType TipoAmora com  amoraVerde  e amoraMadura,  e  criar um atributo tipo:TipoAmora  na  classe Amora. As novas  invariantes seriam:

context Amora

inv: self.tipo = TipoAmora::amoraVerde implies self.contida­>forAll(c : Cesta | c.tipo =         TipoCesta::tipo1))

context Amora

inv: self.tipo = TipoAmora::amoraMadura implies self.contida­>forAll(c : Cesta | c.tipo =         TipoCesta::tipo2))

Nesse exemplo, pode­se transformar as subclasses em  DataTypes  por que as mesmas não 

possuíam   atributos   ou   comportamentos   específicos.   Então,   nem   sempre   modelos   poderão   ser 

transformados dessa forma, e também não será sempre o caso que essa técnica seja a melhor 

alternativa. A arte de balancear diagramas com anotações OCL dependerá da finalidade do modelo.

2.4. MDA, UML e OCL

A essência do MDA é que os modelos são a base para o desenvolvimento de  software. 

Portanto, os modelos devem ser bons, sólidos, consistentes e coerentes. 

As linguagens de modelagem são fundamentais em MDA. Como tanto PIM's, como PSM's  são   transformados   automaticamente,   eles   devem   ser   escritos   em   uma   linguagem   padrão,   bem  definida, que possa ser processada automaticamente por ferramentas. 

Para que se possa aplicar o processo MDA, os modelos devem estar no nível 4 de maturidade  (seção 2.1.1.5.). Pois nesse nível eles são precisos o suficiente para serem transformados de PIM's  para PSM's.

2.4.1. Modelagem com UML/OCL

Muitos dos problemas em modelagem são provocados pelas limitações dos diagramas. Um  diagrama é incapaz de expressar todos os enunciados que devem ser partes de uma especificação. 

Por exemplo, o caso de multiplicidade dinâmica mostrado na seção 2.3.2.8.

Expressões   escritas   em   uma   linguagem   precisa   e   com   base   matemática,   como   OCL,  oferecem   muitos   benefícios   em   relação   aos   diagramas:   não   são   ambíguas,   não   podendo   ser  interpretadas  de   várias   formas;  podem   ser   checadas   automaticamente;   permitem   a  geração  de  modelos derivados, utilizando­se transformações MDA; permitem geração de código. Para que  essas tarefas possam ser automatizadas, o modelo deve conter toda a informação necessária. Uma  ferramenta computacional não consegue interpretar regras em linguagem natural. Regras escritas  em OCL incluem toda a informação necessária para que possam ser utilizadas por ferramentas  automáticas MDA. Desse modo, a implementação é muito mais rápida e eficiente do que se fosse  feita manualmente. 

No entanto, modelos escritos em linguagens que utilizam expressões para representação  geralmente   não   são   facilmente  compreendidos.   Basta   recordar   que   um   código   fonte   pode   ser  considerado  um  modelo  último  de  um  sistema.  A  combinação  de  UML   com  OCL   oferece  a  possibilidade da utilização da linguagem UML em modelos diagramáticos, contornando­se parte  das limitações da linguagem UML pela utilização de expressões OCL.

Como explicitado no exemplo anterior, modelos em diagramas UML, sem expressões OCL, 

podem estar severamente mal especificados. E sem diagramas UML, as expressões OCL farão 

referência  a  elementos  de  modelagem  não  existentes,  pois  não  há  como  especificar  classes  e 

associações em OCL. Assim, somente combinando­se diagramas e restrições é possível especificar 

completamente um modelo.

2.4.2. Metamodelagem com UML/OCL

A construção de metamodelos é a definição de uma linguagem. As mesmas vantagens da  utilização de UML/OCL na construção de modelos são conseguidas na escrita de metamodelos.

No framework MDA novas linguagens precisam ser definidas, mas o mais importante é obter  a   especificação  de   linguagens   existentes.   Muitas   linguagens   de  programação  ainda  não  foram  formalmente definidas. Normalmente a única parte formal em suas especificações é sua gramática,  escrita em BNF.

Novas   linguagens   também   podem   ser   definidas   como   perfis   UML,   desobrigando­se   a  criação de um metamodelo completamente novo para a linguagem. Em vez disso, o metamodelo da  UML é utilizado juntamente com regras extras e um mapeamento dos conceitos da linguagem com  estereótipos UML.

2.4.3. Transformações definidas com UML/OCL

Uma definição de transformação descreve como um modelo escrito em uma linguagem pode  ser transformado em um modelo escrito em outra linguagem. Essa descrição é genérica quando é  independente dos modelos atuais. Ela tem que utilizar conceitos definidos em ambas as linguagens,  ou seja, ela é construída utilizando­se as metaclasses dos metamodelos de ambas as linguagens. 

Uma definição de transformação relaciona metaclasses da linguagem fonte com metaclasses da  linguagem destino.

Como transformações devem ser executadas por ferramentas automáticas, definições de 

transformações devem ser escritas de um forma precisa e não ambígua. Nesse contexto, uma 

expressão OCL pode precisamente indicar quais elementos do metamodelo fonte são utilizados em 

uma certa transformação em determinados elementos do metamodelo destino.

2.5. Metamodelagem utilizando­se o Eclipse

Na  realização dessa monografia utilizou­se a IDE Eclipse, principalmente devido ao fato  dela apresentar, na forma de  plugins, uma série de funcionalidades   interessantes ao projeto em  questão,   como   ferramentas   que   auxiliam   nas   tarefas   de   metamodelagem,   na   realização   de  transformações MDA, na criação de editores gráficos e na validação de modelos.

O Eclipse é uma comunidade cujos projetos são direcionados à construção, em código  aberto, de uma plataforma extensível de desenvolvimento para a construção e gerência de software  em todo o ciclo de vida do último.

No   Eclipse,   diversas   funcionalidades   são   providas   por  frameworks  independentes,  implementados em plugins. Por exemplo, no presente projeto, foram utilizados os plugins:

EMF (Eclipse Modeling Framework) [http://www.eclipse.org/modeling/emf];

GMF (Graphical Modeling Framework) [http://www.eclipse.org/modeling/gmf];

MDT (Model Development Tools) [http://www.eclipse.org/modeling/mdt].

Para a criação dos metamodelos revisados da UML 2.0, utilizou­se o framework EMF. Esse  plugin provê meios para a criação e validação de modelos escritos em ECore com restrições em  OCL, via integração com o  framework  MDT, que provê uma implementação da linguagem OCL  para a avaliação de consultas e restrições em (meta)modelos. ECore é o nome dado ao metamodelo,  implementado em Java, do núcleo da EMF. Ele é praticamente igual à linguagem EMOF (Essential  MOF) [9], com apenas algumas pequenas diferenças, de nomenclatura em sua maioria. Assim, para  evitar confusões, decidiu­se utilizar nomes distintos para esses metamodelos. A linguagem EMOF é  um  subset  da linguagem MOF 2.0 (Meta Object Facility) [http://www.omg.org/mof], assunto da  subseção 2.5.1. 

Na escrita das restrições no ambiente EMF, foi utilizado um subset da linguagem OCL 2.0,  que é definido unicamente baseado no núcleo comum entre UML 2.0 e MOF 2.0 (OCL­MOF  subset), pois a especificação completa da linguagem OCL só pode ser utilizada com a linguagem  UML.

O framework GMF é utilizado para a criação de editores gráficos baseados nos frameworks  EMF e GEF (Graphical Editing Framework) [http://www.eclipse.org/gef]. Esse último possibilita a  construção de editores gráficos a partir de metamodelos, mas devido à sua difícil utilização, foi  criado o GMF, que serve como mediador entre os frameworks EMF e GEF no processo de criação  de um editor gráfico.

A seguir, a subseção 2.5.1 apresentará uma breve exposição da linguagem MOF 2.0. 

2.5.1. MOF

O MOF, criado pelo OMG, provê um  framework  de gerenciamento de metadados e um  conjunto de serviços para habilitar o desenvolvimento e interoperabilidade de sistemas dirigidos a  modelos e metadados.

A criação do MOF foi incentivada por um cenário onde a Internet, ao conectar fontes de  dados e aplicações em todo o planeta, dirigia a expectativa de um fácil e transparente intercâmbio  de dados entre aplicações. Mas, metadados incompatíveis entre diferentes sistemas limitavam o  intercâmbio de dados. Muitas aplicações, ao utilizar modelos proprietários de metadados, impediam  o intercâmbio de dados entre as fronteiras de aplicações, por causa das diferenças entre esses  modelos.

A partir da fundação de modelagem estabelecida pela UML, MOF introduziu os conceitos  de metamodelos formais e modelos de metadados independentes de plataforma (PIM's).

2.5.2. EMF

O framework EMF permite a escrita de metamodelos e, a partir de algumas transformações,  a criação de um editor. É importante salientar que todas as transformações de modelos feitas no  presente projeto não são apresentadas explicitamente como modelos de transformação, e sim como  funcionalidades providas pelo Eclipse, ou seja, para realizar uma transformação entre modelos, o  usuário deve acionar um comando no Eclipse, que  mostrará uma caixa de diálogo, e a partir da  interação  com   o   usuário,  o   Eclipse  coletará  as   informações  adicionais  mínimas   necessárias   à  transformação. Nesse  framework, um metamodelo ECore pode ser transformado em um modelo  Gen, que contém as informações necessárias à criação de um editor. Dependendo do metamodelo  ECore utilizado, poderá haver a necessidade de alteração manual do modelo Gen, para que o mesmo  seja capaz de ser transformado em um editor. Por exemplo, no projeto em questão, o metamodelo  ECore possui algumas operações e meta­atributos especificados em OCL, e em função disso, houve  a necessidade de alterar manualmente o modelo Gen gerado a partir do metamodelo ECore, para  que o processo de transformação do modelo Gen no editor seja capaz de interpretar as expressões  OCL.

2.5.3. GMF

O framework GMF está acima do EMF e permite a transformação de um editor em árvore, 

gerado no framework EMF, em um editor gráfico. O Processo de transformação é semelhante ao 

descrito anteriormente. A partir de um metamodelo ECore, são gerados dois modelos, um modelo 

GMFGraph, que contém informações relativas à visualização de elementos do metamodelo, e um 

modelo GMFTool, que contém informações relativas à barra de ferramentas do editor gráfico. No 

projeto atual, foi necessário alterar o modelo GMFGraph gerado a partir do metamodelo ECore, 

para que as decorações propostas nos perfis de modelagem exibidos no capítulo 3 possam ser  implementadas.   A  partir  dos   modelos  ECore,  GMFGraph   e   GMFTool   foi  gerado  um  modelo  GMFMap, que tem a função de criar mapeamentos entre os três modelos anteriores. Não há como  adicionar as restrições OCL, mostradas nos perfis, no processo de transformação que cria o modelo  GMFMap. Então, houve a necessidade de adicionar essas restrições posteriormente. A partir do  modelo GMFMap, pôde ser criado o modelo GMFGen, que tem a função de gerar o editor gráfico. 

Novamente, houve a necessidade de alterar o modelo GMFGen após a sua criação, para habilitar a 

funcionalidade de validação de modelos no editor gráfico. Feito isso, o modelo GMFGen pôde ser 

transformado no editor e classes Java que implementam as decorações foram adicionadas ao código 

fonte do editor gerado.

3. Das Limitações da Modelagem Conceitual Utilizando­se UML 2.0

Em [Guizzardi, 2005], é exposto um framework para avaliação de linguagens de modelagem. 

Esse  framework  propõe que seja feito um mapeamento entre o metamodelo da linguagem a ser  avaliada e o metamodelo de uma ontologia fundacional escolhida. 

Ontologias   são   modelos   conceituais   consensuais.   Ontologias   fundacionais   são   meta­

ontologias independentes de domínio e que provêem conceitos que serão utilizados na escrita de  outras ontologias.

Uma linguagem será considerada adequada quando todos os seus conceitos possuírem uma  única contraparte na ontologia fundacional. Se existirem conceitos na ontologia que não forem  representados em algum elemento da linguagem, será o caso de incompletude ontológica no nível da  linguagem em questão. Se existirem conceitos na linguagem avaliada que não são representados na  ontologia, eles deverão ser descartados. Se existirem diferentes conceitos ontológicos representados  em um mesmo elemento na linguagem, será o caso de sobrecarga de construtor e a linguagem será  considerada ambígua. E, finalmente, se existirem conceitos ontológicos representados em mais de  um elemento na linguagem, será o caso de excesso de construtores na linguagem. 

O presente capítulo mostra os resultados obtidos em  [Guizzardi, 2005]  pela aplicação do  framework  supracitado   na   avaliação   da   linguagem   UML   2.0,   utilizando­se   como   ontologia  fundacional   a  ontologia  UFO  (Unified  Foundational  Ontology)  proposta  nos   caps.  4   ao  7   de  [Guizzardi, 2005]. O objetivo dessa avaliação e reconstrução da linguagem UML 2.0 foi obter uma  linguagem ontologicamente bem fundada para a construção de ontologias de domínio e modelagem  conceitual.

A UFO, representada parcialmente nas figuras abaixo,  é uma teoria de tipos. Na avaliação  da linguagem UML 2.0, foi utilizado somente o fragmento da ontologia UFO relativo à endurantes,  ou   seja,   objetos.  Assim   como   em   [Guizzardi,   2005],   serão   apresentadas   as   análises   dos   três  fragmentos do metamodelo da UML separadamente, nas seções a seguir.

3.1. Classes e Generalização

A   figura   16   representa   o   fragmento   do   metamodelo   da   UFO   referente   à   classes   e 

generalização.   Nesse   fragmento,   universais   (Universals)  são   padrões   de   características 

A   figura   16   representa   o   fragmento   do   metamodelo   da   UFO   referente   à   classes   e 

generalização.   Nesse   fragmento,   universais   (Universals)  são   padrões   de   características 

Documentos relacionados