ANEXO 3
Modelo Aspectj para Introduções
declare parents: Ponto implements Comparable : esta declaração diz que a classe Ponto agora implementa a interface Comparable. Logicamente um erro a menos que Ponto declare os métodos de Comparable.
declare parents: Ponto extends GeometricObject : esta declaração define que a classe Ponto agora estende a classe ObjetoGeometrico. Um aspecto pode introduzir diversos elementos ao mesmo tempo.
Esta declaração introduz um novo campo e um novo método na classe Ponto
public String Ponto.name;
public void Ponto.setName(String name)
{
this.name = name;
}
Esta declaração introduz o método getName() nas classes Ponto e Linha
public String (Point || Line).getName()
{
return name;
O ponto de corte cflow escolhe os pontos de junção que ocorram entre a entrada e a saída de cada ponto de junção P escolhido pelo ponto de corte, incluindo o próprio P. Assim, são escolhidos os pontos de junção no controle de fluxo dos pontos
de junção escolhidos pelo ponto de corte.
O ponto de corte do tipo cflowbelow escolhe todos os pontos de junção que ocorrem entre a entrada e a saída de cada ponto de junção P escolhidos pelo ponto de
corte mas não incluindo o próprio P.
TIPO DEFINIÇÃO
cflow(Pointcut) Escolhe cada ponto de junção do fluxo de controle de
qualquer ponto de junção P escolhido por Pointcut, inclusive o próprio P
Cflowbelow(Pointcu
t)
Escolhe cada ponto de junção do fluxo de controle de
qualquer ponto de junção P escolhido por Pointcut, mas não o próprio P
Descritores Primitivos Relacionados ao Controle de Fluxo de Execução
Enquanto muitas responsabilidades estão relacionadas com a estrutura de execução do programa, outras são relacionadas com sua estrutura léxica. O AspectJ permite definir pontos de corte que escolham pontos de junção baseados na localização de um código a ser executado.
O ponto de corte do tipo within escolhe pontos de junção onde a execução do código é definida na declaração de um dos tipos de TypePattern. Isto inclui pontos
de junção do tipo inicialização de classe, inicialização de objeto, execução de método e execução de construtor.
TIPO DEFINIÇÃO
within(TypePattern )
Escolhe os pontos de junção cujo código executante esteja definido em um Tipo equivalente a TypePattern. Withincode(MethodP
attern)
Escolhe cada ponto de junção cujo código executante esteja definido em um método cuja assinatura corresponda a
MethodPattern
2) pointcut pegaPonto(Point p): call(*.*(Ponto)) && args(p)
O ponto de corte representado pelo segmento de código numero 1 define como
pontos de junção todas as chamadas a métodos da classe Linha que recebam um tipo
inteiro como argumento disponibilizando o valor deste argumento ao ponto de corte por meio da variável x. O ponto de corte representado pelo segmento de código de número 2 define como pontos de junção todas as chamadas a métodos que recebam um objeto
Ponto como argumento. A variável p disponibilizará o valor deste argumento ao ponto de corte.
A primitiva target permite selecionar pontos de junção cuja origem do evento seja um objeto específico. O ponto de corte descrito no segmento de código abaixo determina como pontos de junção a chamada aos métodos setX(int) e setY(int). A primitiva target(Ponto) garante que estes métodos sejam invocados de alguma instância da classe Ponto. Vejamos:
Pointcut atribuidor(): target(Ponto) && (call(void setX(int)) || call(void setY(int)));
Um ponto de corte do tipo this seleciona os pontos de junção do objeto corrente em execução quando este objeto corrente for uma instância de um tipo em particular.
TIPO DEFINIÇÃO
This(Type or
Id)
Escolhe cada ponto de junção onde o objeto corrente em
execução seja uma instância de Type ou seja do mesmo tipo de Id. Não estarão incluídos pontos de junção de contextos estáticos Target(Type or
Id)
Escolhe cada ponto de junção onde o objeto alvo (objeto sobre o qual uma chamada ou operação sobre campo é aplicada) seja uma instância de Type ou seja do mesmo tipo de Id. Não estarão incluídos chamadas leituras ou atribuições a membros estáticos Args(Type or
Id, ...)
Escolhe cada ponto de junção onde os argumentos são instâncias de um determinado Tipo ou identificador
Descritores Primitivos Relacionados ao Estado
Algumas responsabilidades são relacionadas ao controle de fluxo do programa. O AspectJ provê os descritores cflow e cflowbelow, que capturam pontos de
TIPO DEFINIÇÃO
Handler(Tipo) Escolhe os pontos de junção do tipo execução de exceção cujo Tipo corresponda ao argumento entre os parênteses
Descritores Primitivos Relacionados à Execução de Exceções
TIPO DEFINIÇÃO
AdviceExecution() Escolhe os pontos de junção do tipo advice execution
Descritores Primitivos Relacionados à Execução de Advices
O AspectJ prevê um descritor primitivo para capturar pontos de corte do tipo
execução de advice. Este tipo de descritor pode ser usado para por exemplo filtrar
algum ponto de junção que faça parte do fluxo de execução de algum advice. Um exemplo de tal aplicação para este tipo de descritor pode ser visto no segmento de código abaixo:
aspect TraceStuff {
pointcut myAdvice(): adviceexecution() && within(TraceStuff);
before(): call(* *(..)) && !cflow(myAdvice) { //fazer alguma coisa
} }
Os pontos de corte podem especificar parâmetros formais tipados de forma similar aos métodos Java. Desta forma o AspectJ permite que partes do contexto de execução dos pontos de junção seja exposta. Esta exposição é conseguida através do modelo de parametrização dos pontos de corte.
Sob este enfoque a primitiva args permite expor parte do contexto pontos de
junção. Quando args é especificado, permite a captura da argumentação recebida pelo
evento associado ao ponto de junção possibilitando o retorno deste valor ao ponto de
corte vejamos dois exemplos simples utilizando as classes Linha e Ponto apresentadas
anteriormente:
TIPO DEFINIÇÃO
Call(assinaturaCon
strutor)
Escolhe os pontos de junção do tipo chamada do construtor cuja assinatura do construtor corresponda ao
argumento entre os parênteses. Execution(assinatu
raConstrutor)
Escolhe os pontos de junção do tipo execução construtor cuja assinatura do construtor corresponda ao argumento entre os parênteses.
Initialization(ass inaturaConstrutor)
Escolhe os pontos de junção do tipo inicialização do objeto cuja assinatura do construtor corresponda ao
argumento entre os parênteses. Preinitialization(
assinaturaConstrut
or)
Escolhe os pontos de junção do tipo pre-inicialização do
objeto cuja assinatura do construtor corresponda ao
argumento entre os parênteses.
Descritores Primitivos Relacionados ao Objeto
TIPO DEFINIÇÃO
Staticinitializati on(Tipo)
Escolhe os pontos de junção do tipo execução do inicializador estático cujo Tipo corresponda ao argumento
entre os parênteses
Descritores Primitivos Relacionados à Inicialização da Classe
O AspectJ prevê um descritor primitivo para capturar pontos de corte do tipo
execução de exceção. Para todo ponto de junção deste tipo é considerado um argumento
de retorno que é o valor da exceção sendo manipulada. Este valor pode ser acessado com o uso de um ponto de corte do tipo args(). Assim, um aspecto que capture uma exceção hipotética qualquer antes que ela seja manipulada pode ser escrita conforme abaixo:
Aspect NormalizeFooException {
before(FooException e): handler(FooException) && args(e) {
e.normalize(); }
ANEXO 2
Modelo Aspectj para Pontos de Corte
DESCRITOR TIPO DEFINIÇÃO
Call(assinaturaMét
odo)
Escolhe os pontos de junção do tipo chamada de método cuja assinatura do método seja correspondente ao argumento entre os parênteses
Execution(assinatu
raMétodo)
Escolhe os pontos de junção do tipo execução de método cuja assinatura do método seja correspondente ao argumento entre os parênteses
Descritores Primitivos Relacionados a Método
TIPO DEFINIÇÃO
Get(assinaturaCamp
o)
Escolhe os pontos de junção do tipo referência a campo cuja assinatura do campo corresponda ao argumento entre os parênteses. Campos do tipo constante conforme mencionado não são pontos de junção
Set(assinaturaCamp
o)
Escolhe os pontos de junção do tipo atribuição de campo cuja assinatura do campo corresponda ao argumento entre os parênteses. Campos do tipo constante conforme mencionado não são pontos de junção
Descritores Primitivos Relacionados a Campo
O AspectJ considera para todo ponto de junção do tipo set um argumento de retorno que é o valor sendo atribuído ao campo. Desta forma este valor pode ser acessado com o uso de um ponto de corte do tipo args().
aspect GuardedX {
static final int MAX_CHANGE = 100;
before(int newval): set(int T.x) && args(newval) { if (Math.abs(newval - T.x) > MAX_CHANGE)
throw new RuntimeException(); }
ANEXO 1
Modelo Aspectj para Pontos de Junção
Nome Definição
Method call
quando um método é chamado
Method executio n
quando o corpo do método está sendo executado
Construc tor call
quando o construtor do objeto está sendo chamado
Construc tor executio n
quando o corpo do construtor está sendo executado. Nenhum valor é retornado deste tipo de ponto de junção
Static initiali zer executio n
quando um inicializador estático para a classe é executado. Nenhum valor é retornado deste tipo de ponto de junção
Field referenc e
para campos do tipo não constante. Campos do tipo constante não são pontos de
junção em função do Java os utilizar no processo de inline
Handler executio n
Quando um manipulador de exceção executa. Este tipo de ponto de junção requer um parâmetro que é o tipo de exceção manipulada. Nenhum valor retorna deste tipo de ponto de junção
Advice executio n
S5 Systems Inc. Byte code Optimization, 2002 http://www.s5systems.com/index .shtml?tech4.
SHUDO, Kazuyuku. shuJIT: a Java Just-in-Time Compiler for x86, 2002 http://www.shudo.net/jit.
SUZUKI, Junichi; Yamamoto, Yoshikazu. Extending UML with Aspects: Aspect Support in the Design Phase. Department of Computer Science, Graduate Scholl of Science and Technology, Keio University: Yokohama City, 1999.
VOELTER, Markus. Aspect-Oriented Programming in Java, 2000
http://www.voelter. de/data/articles/aop/aop.html.
WALKER, Robert J.; Baniassad, Elisa L. A.; Murphy, Gail C. An Initial Assessment of Aspect-oriented Programming. Dept. of Computer Science: University of Brithish Columbia, 1999.
XUE, Jingling; Cai, Qiong; Phung, Nguyen Hua. Dynamic and Adaptive Compilation , 2001 http://www.cse.unsw.edu.au/~jxue/jit.html.
HIGHLEY, T. J.; Lack, Michael; Miers, Perry. Aspect Oriented Programming: A Critical Analysis Of A New Programming Paradigm. Programing Languages: CS655 Semester Project from Professor Paul Raynolds, 2000.
HOMEPAGE BY IBM LABS. JIT/400, 1999 http://www.haifa.il.ibm.com/projects /systems/cot/jit400/index.html.
JENSEN, Markus. Jopt - The Java Class File Optimizer, 2000 http://www-i2.informatik.rwth-aachen.de/~markusj/jopt.
JENSEN, Markus. Optimizations, 2001 http://www-i2.informatik.rwth-aachen.de/~ markusj/jopt/htmldoc/node4.html.
KICKZALES, Gregor; Lamping, John; Mendhekar, Anurag; Maeda, Chris; Lopes, Cristina Videira; Loingtier, Jean-Marc; Irwin, John. Aspect-Oriented Programming – Published in proceedings of the European Conference on Object-Oriented Programming (ECOOP), Finland : Springer-Verlag, 1997.
KICKZALES, Gregor; Hilsdale, Eric; Hugumin, Jim; Kersten, Mik; Palm, Jeffrey; Griswold, William G. An Overview of AspectJ. Department of Computer Science, University of British Columbia, Xerox Palo Alto Research Center USA, Department of Computer Science and Engeneering: University of California. San Diego, 2001. LESIECKI, Nicholas. Improve modularity with aspect- oriented programming.
Technical Team Lead, eBlox, Inc., January 2002 http://www-106.ibm.com/developerworks/java/library/j-aspectj/?loc.
LOPES, Cristina Videira; Kickzales, Gregor. Recent Developments in AspectJ™. Xerox Palo Alto Research Center USA, 1998.
LOPES, Cristina; Kiczales, Gregor. Aspect-Oriented Programming with AspectJ™. Xerox PARC Palo Alto Research, 2000 www.parc.xerox.com/aop.
LOPES, Cristina Videira. Aspect-Oriented Programming:An Historical Perspective (What’s in a Name?). Institute for Software Research, University of California : Irvine, 2002.
RICHTER, Jeffrey. Earthweb Networking and Communications: Microsoft & .NET: JIT Compilation and Performance, 2002 http://softwaredev.earthweb.com.
Referências Bibliográficas
APPLE COMPUTER, INC. Automated Code Optimization, 2001:
http://developer.apple.com/techpubs/macosx/Essentials/Performance/Languages/Au tomated_C_ptimization.html.
ASPECT-ORIENTED PROGRAMMING (AOP), 2000. http://www.peterindia.com/ AOP.html.
ASPECTJ DOCUMENTATION AND RESOURCES, 2002. http://eclipse.org/aspectj. ALWIS, Brian de; Gudmundson, Stephan; Smolyn, Greg; Kiczales, Gregor. Coding
Issues in AspectJ. Department of Computer Science, University of British Columbia: Vancouver, 2000.
BLAIR, Lynne; Blair, Gordon S.. The Impact of Aspect-Oriented Programming on Formal Methods. Computing Department, Lancaster University, Bailgrig: Lancaster, 1998.
BOOLLERT, Kai. On Weaving Aspects. Heintzestr, 17 24143 Kiel: Germany, 1999.
BOOLLERT, Kai. AOP Case Study: System Management Application.
Fachhochschule Germany: Bóblingen, 2000.
ERNST, Erik. Separation of Concerns and Then What?. Department of Computer Science, University of Aalborg: Denmark, 2000 .
HARDWIK, Jonathan. Java Compilers, 1997 http://www-2.cs.cmu .edu /~jch /java/com pilers.html.
HARDWIK, Jonathan. Optimizing Java for Speed, 1997 http://www-2.cs.cmu.edu /~jch/java/speed.html
HERRERO, José Luis; Sanchez, Fernando; Lucio, Fabíola; Toro, Miguel. Introducing Separation Of Aspects At Design Time. Departamento de Informática, Universidad de Extremadura: Sevilha, 1999.
Capítulo VI
Conclusão
O objetivo em utilizar a POA como ferramenta de projeto de software reutilizáveis foi alcançado com sucesso. Foi possível evidenciar que a modularização das RCE possibilitou a reutilização do projeto Figuras Flutuantes em dois contextos diferenciados, sem a necessidade de adaptações de qualquer natureza nas classes do sistema.
Como resultado final foi possível obter dois ganhos que nas abordagens de programação OO e procedural encontram-se em posições antagônicas. São eles:
· Aumento do grau de especialização: os atributos e métodos necessários para a execução das instâncias no contexto específico C1 foram agregadas apenas quando as instâncias foram executadas neste contexto;
· Manutenção do grau de reusabilidade: o mesmo conjunto de classes foi executado nos dois contextos diferenciados C1 e C2, mesmo sob o fato de que ambos exigem um conjunto diferenciado de operações.
6.1. Sugestão para Trabalhos Futuros
Como sugestão para trabalhos futuros propõe-se o desenvolvimento de uma ferramenta que modularize as RCE identificadas nas classes do sistema de forma automatizada.
· Não existem notações formais para representação dos aspectos concretos ou abstratos e neles as suas operações;
· Torna-se difícil avaliar o grau de abrangência dos aspectos sobre as classes do sistema ou seja quais classes um aspecto realmente afeta. Isto gera:
- Dificuldade na manutenção dos aspectos pois altera-los pode afetar diversas
classes do sistema;
- As classes podem implementar pontos de corte nomeados e estes pontos de corte
podem ser reusados por diversos aspectos. É necessária uma representação formal que permita visualizar quais aspectos reusam um determinado ponto de corte pois altera-lo ou aos aspectos que os reusam podem gerar reflexos sobre o sistema.
A separação de responsabilidades mostrou-se viável como forma de diminuir a complexidade do código e aumentar o grau de reusabilidade dos componentes do sistema. Mas conforme pôde ser percebido durante a implementação do aplicativo Figuras Flutuantes, é fundamental um mecanismo que permita a representação formal dos aspectos. As seguintes vantagens são descritas
· Documentação e aprendizado - os aspectos devem ser documentados gerando um aprendizado mais fácil a respeito do seu relacionamento com os componentes do sistema; · Reuso - documentar como um aspecto foi construído(sua estrutura) e a forma pela
qual ele pode afetar os componentes do sistema pode determinar sua utilização em diferentes domínios.
Existem propostas como a extensão da UML pela adição de uma nova metaentidade para representar o aspecto. No entanto encontram-se ao nível de mera proposição. Desta forma necessitam ser alvo de estudos e avaliações que as permitam alçar ao nível de um formalismo que possa ser aceito e utilizado para suprir esta deficiência do modelo orientado a aspectos.
classe(s) afetada(s). Ocorre que alterações nas classes do sistema ou nos requerimentos relativos ao contexto podem gerar alterações nos aspectos no seguinte sentido:
· Em acordo com a convenção de classificação das RCE aqui adotada, uma RCE que passe a ser requerida pelo conjunto total de contextos passará a ser implementada como membro de classe;
· Da mesma forma uma operação que passe a ser requerida apenas por um conjunto restrito de contextos poderá passar a ser modularizada como uma RCE em um aspecto.
Novamente surgem dificuldades de visualização entre o aspecto que modulariza a RCE e o conjunto de classes por ele afetadas. Novamente o motivo é o fato de que a POA não prevê mecanismos que permitam a visualização dos aspectos em tempo de projeto.
5.4. Crítica ao Modelo Orientado a Aspectos
No decorrer do desenvolvimento das atividades deste trabalho surgiram diversos temas que oferecem pontos de vista críticos ao modelo orientado a aspectos. Não somente ao modelo da forma como foi concebido mas também a outros pontos considerados como relevantes por diversos autores. Entretanto estas abordagens não são o foco deste trabalho e podem ser vistas em diversas fontes (ALWIS et al, 2000, HERRERO et al, 1999, SUZUKI & YAMAMOTO, 1999, ERNST, 2000).
É comentado neste trabalho apenas uma deficiência que é a falta de padrões que possibilitem a representação dos aspectos em tempo de projeto. Existe realmente a falta de atenções no que diz respeito a técnicas que permitam a documentação dos aspectos. Foi possível verificar que (KICZALES, 2001) é o idealizador deste paradigma porém em suas publicações trata os aspectos apenas no tempo de implementação.
Esta deficiência gera dificuldades pois impede uma visão mais apurada do relacionamento entre as classes e os aspectos. A falta de um formalismo que permita a documentação dos aspectos como uma entidade do diagrama de classes implica nas seguintes dificuldades:
aspectos. Foram modularizados como RCE o seguinte conjunto de membros das classes:
- Duas declarações de importação de bibliotecas; Trinta atributos; Sete
implementações de métodos.
· A especialização das classes de forma que elas agora implementam apenas as operações realmente comuns aos contextos C1 e C2. O resultado foi a diminuição do código das classes em aproximadamente 54%;
A eliminação das referências entre as classes do sistema eliminando a dependência gerada na versão OO.
Figura 5.17 – Aplicativo Figuras Flutuantes com a Modularização das RCE
Entretanto surge uma questão semelhante àquela encontrada na modularização das responsablidades comuns. Não há mecanismos que garantam a evolução do aspecto que modulariza as RCE no que diz respeito à evolução da(s)
· Com a identificação e modularização das RCE de deslizamento, colisão e conexão as instâncias das classes Circulo, Triangulo, Retangulo passaram a herdar apenas as operações de pintura – métodos pintaFigura();
· As instâncias a classe Display passaram a herdar apenas as operações referentes ao suporte de pintura das figuras – métodos inicializaImagem(), paint() e update(); · A classe Registrador passou a não herdar mais o método pegaFiguras().
Todo o conjunto de atributos e bibliotecas de recursos associados a estas operações passaram a não ser mais agregados pelas instâncias inseridas no contexto C2. As instâncias inseridas no contexto C1 entretanto passaram a agregar estes recursos através das RCE modularizadas. As classes do sistema passaram a implementar apenas o conjunto de atributos e métodos comuns aos dois contextos idealizados para o aplicativo Figuras Flutuantes. Os demais métodos e atributos referentes às operações dos esquemas de deslizamento, colisões e conexões são agregadas apenas pelas instâncias inseridas no contexto C1.
A fig. 5.17 apresenta a caracterização do ambiente de execução após a modularização das RCE. Observe-se que a área de cor cinza, que representa a implementação das operações modularizadas como RCE, se estendem apenas sobre o retângulo da esquerda que é a representação do contexto C1. O retângulo da direita que é a representação do contexto C2 não é afetado.
A modularização das RCE de deslizamento, conexão e colisão nos aspectos
Navegacao, trataColisao, pintaLinhas, reduzTempoDeVida e protecaoDoRegistro
permitiu:
· Que as instâncias das classes Display, Circulo, Retangulo, Triangulo e Registrador quando inseridas no contexto C2 não herdem o conjunto que para elas é obsoleto de operações somente aplicados ao contexto C1;
· Que estas classes quando inseridas no contexto C1 agreguem o conjunto de operações de deslizamento, conexão e colisão por meio das RCE modularizadas nos
mecanismos que garantam a permanente evolução dos aspectos em função da evolução da(s) classe(s) por ele afetada(s).
Não há visibilidade alguma em tempo de projeto sobre quais classes e operações são afetadas por um aspecto que modulariza um determinado tratamento de erros. Surgem assim duas situações que podem gerar algum tipo de inconsistência no relacionamento classe-aspecto. São elas:
· Novas operações implementadas na classe geram alterações nos advices;
· Operações antigas que venham a ser alteradas de modo a eliminar ou alterar a natureza do seu tratamento de erros também geram alterações nos advices.
A única forma de administrar as inconsistências que podem ser geradas pelas situações acima citadas é a constante verificação do código dos aspectos e classes. Esta não é uma solução prática e pode vir a se tornar uma tarefa trabalhosa tendo em vista a complexidade que o sistema pode vir a adquirir. Os efeitos são os seguintes: · Advices inúteis poderão ser esquecidos poluindo o código do aspecto;
· Advices necessários para o tratamento de erros de alguma operação poderão não ser implementados.
Se por simples esquecimento as inclusões e alterações das necessidades de tratamento de erros não forem tratadas pelos aspectos haverá deficiência no tratamento de exceções.
5.3.3.2. Benefícios da Modularização das RCE
As RCE do aplicativo Figuras Flutuantes foram identificadas e modularizadas com o uso da metodologia sugerida no cap. 4. Como resultado obteve-se um conjunto de classes reutilizáveis que podem ser inseridas nos dois contextos distintos C1 e C2 sem a necessidade de customizações.
O benefício mais relevante foi o fato de que a modularização das RCE permitiu de certa forma especializar o mecanismo de herança do modelo OO da seguinte forma:
5.3.3. Os Benefícios Obtidos
A migração do aplicativo para uma abordagem orientada a aspectos possibilitou a obtenção de benefícios relativos às deficiências detectadas e descritas na seção 4.2.2. possibilitando a obtenção de vários itens de otimização.
5.3.3.1. Benefícios da Modularização das Responsabilidades Comuns
O modelo orientado a aspectos permitiu de uma forma natural modularizar no aspecto trataExecao todo o código referente ao tratamento de exceções. O resultado pôde ser visto na fig. 5.4 que mostra a implementação deste aspecto onde cada advice implementado faz uso de um ponto de corte nomeado declarado como membro da própria classe. Optou-se então por uma abordagem per-class para a declaração dos
pontos de corte deste aspecto.
É interessante mencionar que a flexibilidade oferecida pelo modelo de aspectos permitiria também uma abordagem centralizada onde todos os pontos de corte poderiam ter sido declarados dentro do próprio aspecto trataExcecao. Com a modularização do tratamento de exceções adquiriu-se:
· Um nível mais alto de modularização visto que o tratamento de exceções referentes às operações de pintura e navegação, entre outras, puderam ser modularizados em um único aspecto ao invés de estar disperso pelas classes do sistema;
· Um nível mais alto de reusabilidade visto que o código referente ao tratamento de um mesmo tipo de exceção pode ser reutilizado por mais de uma classe em mais de um método sem a ocorrência de replicação de código;
· A eliminação da replicação de código provocada pelo tratamento de exceções por meio da implementação do aspecto trataExcecao. O código replicado foi eliminado em dezoito pontos distintos das classes do sistema num total de sete classes beneficiadas, ou seja, 100% das classes implementadas.
A POA mostrou vantagens reais no que diz respeito à modularização e reutilização do código recorrente do tratamento de exceções. Mas por outro lado não há
aspect protecaoDoRegistro {
after() returning(): (call(void Registrador.Registra(Figura)) ||
call(void Registrador.Apaga(Figura))) && within(Figura)&& (withincode(new(..)) ||
withincode(void morre()))) {
throw new IllegalAccessError(
"Este é um acesso ilegal a " + thisJoinPoint + "\n" + "Apenas o construtor e o método morre() de Figura " + "\n" +
"podem invocar operações da classe Registrador. "); }
}
Figura 5.16 – O Aspecto protecaoDoRegistro
Se analisarmos o advice implementado para o aspecto mostrado na fig. 5.16 é possível separá-lo em quatro segmentos distintos que são:
· call(void Registrador.Registra(Figura)) || call(void Registrador.Apaga(Figura)): usa a primitiva call para especificar como
pontos de junção as chamadas aos métodos registra(Figura) e apaga(Figura). O
operador lógico OU aqui representado pelo símbolo ‘| |’ determina que o advice deverá ser executado quando um ou outro ponto de junção for encontrado;
· !(within(Figura)&& (withincode(new(..)) || withincode(void morre()))): determina a negação da seguinte sentença – o ponto de junção, quando encontrado, deverá estar contido dentro de um objeto da classe Figura (!(within(Figura)) e neste dentro do seu construtor ou dentro do método morre() - ((withincode(new(..)) || withincode(void morre()));
· after() returning(): determina a execução à partir do retorno normal do
ponto de junção encontrado.
Em suma, o advice será executado quando houver a invocação de um método registra() ou de um método apaga() cuja origem não seja exclusivamente o construtor ou o método morre() de um objeto da classe Figura.
Sendo executado o advice levantará uma exceção onde a forma especial
Quando o ponto de junção declarado no ponto de corte navegaFigura() é encontrado, ocorre a suspensão do fluxo de execução no tipo que originou o ponto de
junção. O objeto retornado permanece como objeto corrente no momento em que a
variável tempoRestante declarada no corpo do advice invoca o método pegaTempoDeVida() do objeto adquirindo o valor atual do atributo tempoVida desta
instância.
Sendo este valor maior que zero, o formato especial proceed() devolve o fluxo de execução ao objeto para que ele transcorra de forma natural. Caso contrário, o método morre() do tipo é invocado determinado o fim do tempo de vida do objeto. 5.3.2.5. O Aspecto protecaoDoRegistro
Este aspecto é utilizado para reforçar uma diretriz do projeto que é a seguinte: os métodos registra() e apaga() da classe Registrador podem ser invocados em apenas dois pontos da classe Figura que são seu construtor e o método morre(). A invocação destas primitivas a partir de qualquer outro ponto determinará o levantamento de exceção. São empregados neste advice três primitivas:
· call : determina como ponto de junção a chamada de métodos;
· within : associada à primitiva call permite determinar o tipo associado o ponto de
junção encontrado;
· withincode: associado à primitiva call possibilita a identificação da operação associada ao ponto de junção encontrado.
Os três operadores lógicos que na sintaxe AspectJ (&&, | | e !) são os operadores lógicos AND, OR e NOT respectivamente. São empregados para determinar o resultado da sentença. É aplicada também uma forma especial ThisJoinPoint que oferece informações reflectivas sobre o ponto de junção encontrado.
nomeação permite seu reuso em múltiplos advices sem a necessidade de rescrever o conjunto de pontos de junção.
Outro elemento até agora não apresentado é o advice do tipo around(). Este tipo de advice, diferentemente dos advices after() e before(), permite algum controle sobre o fluxo de execução na origem do ponto de junção. Este controle é conseguido pela combinação do formato especial proceed() que é disponível apenas para este tipo de advice e é mostrado na fig. 5.15.
aspect reduzTempoDeVida {
pointcut navegaFigura(Figura figura): target(figura) && (call(void
Figura+.navega()));
void around (Figura figura): navegaFigura(figura) {
int tempoRestante = figura.pegaTempoDeVida(); if (tempoRestante > 0) { figura.reduzTempoDeVida(); proceed(figura); } else figura.morre(); } }
Figura 5.15 – O Aspecto reduzTempoDeVida
Se analisarmos o advice implementado para o aspecto reduzTempoDeVida é possível separá-lo em quatro segmentos distintos que são:
· target(figura) && (call(void Figura+.navega(): a diretiva call determina como ponto de junção a chamada ao método navega() de todos os subtipos da classe Figura, neste caso objetos Circulo, Retangulo e Triangulo. A primitiva target() determina como objeto origem da operação uma instância desta classe;
· void around (Figura figura):navegaFigura(figura): o advice
around(), quando executado, retorna uma referência ao objeto Figura que originou o ponto de junção. Esta referência retorna na variável figura declarada no advice.
· call(Graphics Figura+.pintaFigura(Graphics, double, double)): usa a primitiva call para especificar como ponto de junção as chamadas ao método pintaFigura() de qualquer subtipo da classe Figura;
· after(Figura figura) returning(Graphics g): determina que após a execução do corpo do ponto de corte, havendo retorno normal do método
pintaFigura(), serão armazenados na variável figura uma referência ao objeto de
origem do ponto de junção e na variável g uma referência ao objeto Graphics recebido como parâmetro pelo ponto de corte;
· target() && call(): o operador lógico ‘E’ , aqui determinado pelo símbolo
‘&&’ que é utilizado para reforçar a determinação do ponto de corte de que o advice
somente será executado para pontos de junção cuja origem seja um objeto da classe
Display. Não serão válidos quaisquer outros pontos de junção eventualmente
encontrados cuja origem não seja o tipo especificado pela primitiva target().
Sendo encontrado o ponto de junção especificado o advice é executado e o método detectaColisao(g) é invocado. Este método é introduzido na classe Display, bem como os métodos ocorreuColisao() e manipulaColisao() pelo mecanismo de introduções.
5.3.2.4. Aspecto reduzTempoDeVida
Na versão OO do aplicativo a redução do tempo de vida dos objetos Figura foi implementado à dentro do método manipulaNavegação() da classe Display. Tal escolha foi efetuada em função da convenção adotada para o projeto onde o tempo de vida do objeto é reduzido à medida em que ele se movimenta sobre o plano.
A justificativa para implementação do aspecto reduzTempoDeVida é que a classe Display, a qual representa o plano onde os objetos Figura flutuam, não tem como responsabilidade primária dar suporte à operação de redução do tempo de vida das figuras.
Observamos para este aspecto a nomeação explícita de um ponto de corte. Nos aspectos anteriormente apresentados os pontos de corte são ditos anônimos. A
5.3.2.3. O Aspecto trataColisao
Na versão OO do aplicativo o tratamento de colisões foi implementado à partir do método trataColisao() da classe Display. É possível encapsular no aspecto
trataColisao a responsabilidade relativa a estas operações.
Isto permitirá que a classe Display implemente apenas sua responsabilidade primária que é suportar a pintura das figuras no plano, podendo agregar o aspecto de tratamento de colisões quando o contexto assim o exigir.
A implementação do aspecto trataColisoes pode ser vista na fig. 5.14 que apresenta a declaração de um advice do tipo after() e três elementos do tipo Introdução.
aspect trataColisao {
after(Figura figura) returning(Graphics g): target(figura) && call(Graphics Figura+.pintaFigura(Graphics, double, double)) {
figura.pegaDisplay().detectaColisao(g); }
public void Display.detectaColisao(Graphics g) {...}
static boolean Display.ocorreuColisao(Figura a, Figura b) {...}
private void Display.manipulaColisao(Graphics g, Figura a, Figura b)
{...} }
Figura 5.14 –O Aspecto trataColisao
O aspecto trataColisao concentra todas as operações relativas ao tratamento de colisões do aplicativo. A classe Display não declara mais estes métodos livrando-se desta responsabilidade que conforme convencionado no cap. 4 é caracterizada como uma RCE. Ocorre então um processo de ‘limpeza’ da estrutura desta classe. Se analisarmos o advice implementado para o aspecto é possível separá-lo em quatro segmentos distintos que são:
· target(display): determina que a origem do ponto de junção a ser encontrado seja uma instância da classe Display;
5.3.2.2. O Aspecto pintaLinhas
Na versão OO do aplicativo o esquema de conexões foi implementado à partir do método pintaLinhas() da classe Linha. A classe Display tem sua participação nas operações do esquema de conexões por meio do método atualizaLinhas(). A justificativa para implementação do aspecto pintaLinhas são as seguintes:
· A classe Display, a qual representa o plano onde os objetos Figura flutuam, não tem como responsabilidade primária dar suporte às operações do esquema de conexão das figuras e aplicada;
· Aplicar a classe Display a um contexto onde o esquema de conexões fosse diferenciado ou não existisse, como é o caso do contexto C2, tornaria necessário customizações manuais de modo a remover as referências às operações deste esquema;
· As referências à classe Linha dentro da classe Display determinam um grau de dependência entre as duas classes visto que elas referenciam uma à outra.
A implementação do aspecto pintaLinhas pode ser vista na fig. 5.13 que apresenta a declaração de um advice do tipo after() e um elemento do tipo introdução.
aspect pintaLinhas {
after(Display display) returning(Graphics g): target(display) && (call(public Graphics getGrafico(Graphics)))
{
display.atualizaLinhas(g); }
public void Display.atualizaLinhas(Graphics g) {...} }
Figura 5.13 – O Aspecto pintaLinhas
Este advice é implementado de forma similar ao advice do aspecto
Navegacao. Entretanto, quando o ponto de junção é encontrado é invocado o método atualizaLinhas(). Este método é introduzido na classe Display por meio de um elemento
O aspecto Navegacao concentra agora todas as operações relativas ao
esquema de deslizamento do aplicativo. As classes Display e Figura não declaram mais estes métodos livrando-se desta responsabilidade que conforme convenção adotada no cap. 4 é caracterizada como uma RCE.
Ocorre então um processo de ‘limpeza’ da estrutura destas classes. Se analisarmos o advice implementado para o aspecto é possível separá-lo em quatro segmentos distintos que são:
· target(display): determina que a origem do join point a ser encontrado seja uma instância da classe Display;
· call(public Graphics getGrafico(Graphics)): usa a primitiva call para especificar como pontos de junção as chamadas ao método getGrafico(Graphics);
· after(Display display) returning(Graphics g): determina que após a execução do corpo do ponto de junção, havendo retorno normal do método
getGrafico(Graphics), serão armazenados na variável display uma referência ao
objeto de origem do ponto de junção e na variável g uma referência ao objeto
Graphics recebido como parâmetro pelo ponto de junção;
· target() && call(): o operador lógico ‘E’ , aqui determinado pelo símbolo
‘&&’ que é utilizado para reforçar a determinação do ponto de corte de que o advice
somente será executado para pontos de junção cuja origem seja um objeto da classe
Display. Não serão válidos quaisquer outros pontos de junção eventualmente
encontrados cuja origem não seja o tipo especificado pela primitiva target().
Sendo encontrado o ponto de junção especificado o advice é executado e o método manipulaNavegacao(g) é invocado. Este método é introduzido na classe
Display, bem como os métodos navega() das classes Círculo, Retângulo e Triangulo
pelo mecanismo já apresentado chamado introdução. Conforme já visto as introduções são utilizados para introduzir novos membros em uma classe.
instâncias da classe. Segue adiante a descrição dos aspectos implementados e que modularizam as RCE classificadas anteriormente.
5.3.2.1. O Aspecto Navegacao
Na versão OO do aplicativo o esquema de deslizamento foi implementado à partir do método navega(), herdado da superclasse Figura e sobrescrito nas subclasses
Circulo, Retangulo e Triangulo. A classe Display tem sua participação nas operações do
esquema de deslizamento por meio do método manipulaNavegação(). A justificativa para implementação do aspecto Navegacao são as seguintes:
· A classe Display, a qual representa o plano onde os objetos Figura flutuam, não tem como responsabilidade primária dar suporte às operações de deslizamento das figuras;
· A implementação do esquema de deslizamento contido nestas classes pode ser considerado como uma responsabilidade secundária pois, aplicando estas classes ao contexto C2, o esquema de deslizamento não existe.
A implementação do aspecto Navegacao pode ser vista nna fig. 5.12 pela declaração de um advice do tipo after() e cinco elementos do tipo introdução.
aspect Navegacao {
after(Display display) returning(Graphics g): target(display) && (call(public Graphics getGrafico(Graphics)))
{
display.manipulaNavegacao(g); }
public void Display.manipulaNavegacao(Graphics g) {...} private void Circulo.navega() {...}
private void Triangulo.navega() {...} private void Retangulo.navega() {...} }
Cabe frisar que uma alternativa diversa à modularização destas RCE em aspectos seria declarar classes intermediárias que implementassem estas operações. Como resultado desta abordagem classes intermediárias encapsulariam as operações de deslizamento, colisão e conexão. É uma alternativa que preserva a diretriz de modularização da OO mas menos desejável sob os seguintes aspectos:
· Menor performance - teríamos inúmeras chamadas dos objetos Figura aos métodos destas classes intermediárias sempre que fosse necessária a execução de uma destas operações. Isto é menos otimizado em termos de velocidade de execução se compararmos a uma classe que invoca os próprios métodos;
· Maior dependência entre módulos - sendo que os objetos da classe Figura e
Display referenciariam estas classes intermediárias, a única forma de inseri-las em
um novo contexto seria customizá-las manualmente para alterar ou talvez remover estas referências;
· Dificuldade de restrição de acesso - nada impediria que um objeto da classe
Círculo invocasse uma operação de navegação para um objeto Retangulo.
Por outro lado a modularização destas RCE em aspectos traz as seguintes vantagens:
· Maior performance - a operação, quando exigida pelo contexto, pode ser introduzida diretamente na classe possibilitando que o lookup seja sempre relativo a métodos da própria classe;
· Inexistência de dependência entre módulos - não existe qualquer forma de dependência entre o aspecto e a classe possibilitando que esta possa ser introduzida em outro contexto sem necessidade de customizações manuais;
· Total restrição ao acesso - um aspecto pode introduzir membros privados em uma classe, restringindo assim o acesso a estes membros.
E cabe ainda frisar uma das maiores vantagens obtidas: as RCE podem ser agregadas apenas quando são realmente requeridas afetando apenas determinadas
Tabulação RCE Classe : Registrador LISTA DE CONTEXTOS OPERAÇÕES 1 (C1) 2 (C2) 3 4 ... 5 ... 6 ... 7 ... 8 ... 9 ... 10 ... TAO 1 OPERAÇÕES DE PROTEÇÃO DO REGISTRO X 50% 2 OUTRAS OPERAÇÕES DO REGISTRO DOS OBJETOS
X X 100%
Figura 5.11 – Tabulação RCE da Classe Registrador
Com a aplicação da tabela RCE sobre a classe Registrador é obtido como resultado que as operações de proteção do registro não são aplicadas ao conjunto total de contextos C1 e C2. Em acordo com a simples convenção aqui adotada isto implica nos seguintes fatos:
· Os métodos e atributos relativos à estas operações são caracterizados como RCE; · Serão então modularizados na forma de aspectos.
A determinação da TAO das operações implementadas por estas classes para os contextos C1 e C2 descritos anteriormente gera o seguinte resultado:
· Nas subclasses de Figura as operações do esquema de navegação não são aplicadas a todos os contextos;
· Na classe Display as operações de suporte aos esquemas de colisão, conexão e navegação não são aplicadas a todos os contextos;
· As operações de proteção do registro implementadas na classe Registrador só se aplicam ao contexto C1.
Conforme dita o padrão de conduta aqui assumido para condução do processo de classificação das RCE, estas operações passarão a ser modularizadas em aspectos. As demais serão mantidas nas classes como parte de sua estrutura primária.
· Os métodos e atributos relativos à estas operações são caracterizados como RCE; · Serão então modularizados na forma de aspectos;
· A fig. 5.10 mostra a aplicação da tabela RCE sobre a classe Display. A TAO para as operações podem ser facilmente visualizadas.
Tabulação RCE Classe : Display
LISTA DE CONTEXTOS OPERAÇÕES 1 (C1) 2 (C2) 3 4 ... 5 ... 6 ... 7 ... 8 ... 9 ... 10 ... TAO 1 OPERAÇÕES DE TRATAMENTO DE COLISÃO X 50% 2 OPERAÇÕES DO ESQUEMA DE NAVEGAÇÃO X 50% 3 OPERAÇÕES DO ESQUEMA DE CONEXÕES X 50% 4 OUTRAS OPERAÇÕES DE MANIPULAÇÃO DOS DADOS
X X 100%
Figura 5.10 – Tabulação RCE da Classe Display
Com a aplicação da tabela RCE sobre a classe Display é obtido como resultado que as operações do esquema de deslizamento, navegação e colisão não são aplicadas ao conjunto total de contextos C1 e C2. Em acordo com a convenção aqui adotada isto implica no seguinte fato: os métodos e atributos relativos à estas operações são caracterizados como RCE.
Serão então modularizados na forma de aspectos. A fig. 5.11 mostra a aplicação da tabela RCE sobre a classe Registrador. A TAO para as operações podem ser facilmente visualizadas.
No caso específico do aplicativo Figuras Flutuantes as operações de deslizamento, colisão e conexão determinam o fator de reusabilidade das classes do sistema porém tornam-se obsoletas em função da inserção de suas instâncias no contexto C2. Será então conduzido o processo de modularização das operações de deslizamento, colisão e conexão na forma de aspectos, visto que elas assumem a característica de serem responsabilidades do tipo RCE. Como forma de obter uma visualização mais facilitada da taxa de aplicabilidade destas operações ao conjunto total de contextos é aplicado sobre estas classes a tabulação RCE sugerida anteriormente no cap 4. Vide fig. 5.9 a seguir.
Tabulação RCE Classe : Circulo, Retangulo,
Triangulo LISTA DE CONTEXTOS OPERAÇÕES 1 (C1) 2 (C2) 3 4 ... 5 ... 6 ... 7 ... 8 ... 9 ... 10 ... TAO 1 OPERAÇÕES DE PINTURA X X 100% 2 OPERAÇÕES DO ESQUEMA DE NAVEGAÇÃO X 50% 3 OUTRAS OPERAÇÕES DE MANIPULAÇÃO DOS DADOS X X 100%
Figura 5.9 – Tabulação RCE das Classes Circulo, Retangulo e Triangulo
A fig. 5.9 apresenta a aplicação da convenção de classificação sugerida sobre as classes Display, Circulo, Triangulo, Retangulo e Registrador. Ela torna-se útil para que se possa observar a taxa de aplicação das operações das classes com base nos contextos C1 e C2. A figura acima mostra a aplicação da tabela RCE sobre as
subclasses de Figura. É obtido como resultado que as operações do esquema de
navegação não são aplicadas ao conjunto total de contextos C1 e C2. Em acordo com a convenção aqui adotada sto implica nos seguintes fatos:
Como pôde ser visto na descrição das características do aplicativo as instâncias das classes do sistema podem ser eventualmente inseridas no contexto particular C1. Pôde ser verificado que as figuras são conectadas entre si por linhas à medida que são criadas, flutuam em alguma direção por algum tempo e são apagadas do plano quando colidem umas com as outras ou expira seu tempo de vida. Foi verificado, também, que as instâncias das classes do sistema quando criadas podem também vir a serem inseridas num contexto diferenciado de C1 que é o contexto C2.
Pôde ser verificado que neste outro contexto os requisitos são totalmente diferenciados do primeiro nos seguintes termos:
· As figuras não flutuam e são apenas entidades estáticas no plano e por conseqüência não irão colidir entre si como acontece no contexto C1;
· Não há linhas que as conectem a outras figuras já existentes no plano no momento de sua criação;
· O tempo de vida das figuras não é limitado, de modo que após criadas elas permanecem pintadas de forma definitiva sobre o plano.
Como conseqüência as operações que tratam do deslizamento, colisão e conexão destas figuras no plano tornam-se obsoletas no contexto C2. Se observarmos a classe Display nos deparamos com uma situação semelhante à anterior. O plano projetado para o aplicativo tem como função básica suportar a pintura das figuras. Entretanto esta classe implementa também operações que possibilitam o tratamento da colisão e da conexão.
É ineressante frisar que foram projetados apenas dois contextos diferenciados para as classes do sistema Figuras Flutuantes. Mas sem dúvida as possibilidades são inúmeras e novas operações são implementadas e excluídas à medida que torna-se necessário ampliar ou restringir o aspecto de reusabilidade das classes. Porém conforme mencionado à medida que novos contextos se abrem para a classe o conjunto de operações que ela passa a implementar pode se tornar muito extenso.
Circulo.navega(...):" + e); } after(Retangulo rt) throwing(Exception e) : Retangulo.erroNavegando(rt) { System.out.println("Erro no método Retangulo.navega(...):" + e); } after(Display ds) throwing(Exception e) : Display.erroNavegando(ds) { System.out.println("Erro no método Display.manipulaNavegacao(...):" + e); }
//**advices para tratamento de colisao after(Display ds) throwing(Exception e) : Display.erroDetectandoColisao(ds) { System.out.println("Erro no método Display.detectaColisao(...):" + e); } after(Display ds) throwing(Exception e) : Display.erroManipulandoColisao(ds) { System.out.println("Erro no método Display.manipulaColisao(...):" + e); }
//**advices para tratamento da leitura do registrador after(Display ds, Figura[] lgf) throwing(Exception e) : Display.erroLendoRegistrador(ds, lgf)
{
System.out.println("Erro lendo registrador...->" + e); }
}
Figura 5.8 – Aspecto trataExcecao
5.3.2. A Modularização das RCE
Para a identificação das RCE das classes foram escolhidas as classes
Display, Círculo, Retangulo, Triangulo e Registrador. Esta escolha foi dirigida pelo
fato destas classes estarem diretamente ligadas às operações que diferenciam os contextos C1 e C2 descritos anteriormente.
package ContextoC1; aspect trataExcecao {
//**advices para tratamento dos procedimentos de pintura after(Circulo cr) throwing(Exception e) : Circulo.erroPintando(cr) { System.out.println("Erro no método Circulo.pintaFigura(...):" + e); } after(Triangulo tr) throwing(Exception e) : Triangulo.erroPintando(tr) { System.out.println("Erro no método Triangulo.pintaFigura(...):" + e); } after(Retangulo rt) throwing(Exception e) : Retangulo.erroPintando(rt) { System.out.println("Erro no método Retangulo.pintaFigura(...):" + e); } after(Display ds) throwing(Exception e) : Display.erroPintandoLinha(ds) { System.out.println("Erro no método Display.atualizaLinhas(...):" + e); } after(Display ds) throwing(Exception e) : Display.erroPintando(ds) { System.out.println("Erro no método Display.manipulaPintura(...):" + e); }
//**advices para tratamento dos procedimentos de navegação after(Triangulo tr) throwing(Exception e) : Triangulo.erroNavegando(tr) { System.out.println("Erro no método Triangulo.navega(...):" + e); } after(Circulo cr) throwing(Exception e) : Circulo.erroNavegando(cr) { System.out.println("Erro no método
exceções seriam facilmente visualizados em um único aspecto. Entretanto importante lembrar que a todo momento novas operações são implementadas e novas cláusulas de tratamento de erros são incluídas no código das classes do sistema.
Realmente nada impediria que estas novas operações passassem desapercebidas na manutenção dos aspectos e deixassem de ser incluídas. Por considerar este motivo como maior desvantagem – embora não profundamente estudada aqui - decidimos por descartar a abordagem centralizada e optar pela segunda hipótese.
Considerando o problema de manutenção acima mencionado a segunda opção parece realmente mais vantajosa. Ao contrário da opção anterior totalmente centralizada, cada classe declararia o seu próprio conjunto de pontos de corte representativos às suas próprias cláusulas de tratamento de erros. Surge então uma concordância com o ponto de vista de (ALWIS et al, 2000) que afirma haver uma visualização mais fácil do conjunto de pontos de junção de cada classe.
É plausível presumir que, à medida que novas operações forem incluídas, estes pontos de corte possam realmente ser alterados com menor probabilidade de esquecimento por parte do programador - embora não haja garantias quanto a isso.
Também é vantajoso do ponto de vida da clareza do código de aspectos se a nomenclatura dos pontos de corte for clara no que se refere à sua finalidade. A versão orientada a aspectos do aplicativo Figuras Flutuantes implementa a modularização do tratamento de exceções em um único aspecto chamado trataExcecao. Este aspecto implementa um conjunto de 12 advices onde cada advice é destinado a um tipo específico de exceção.
A justificativa para a adoção desta diretriz diz respeito somente à legibilidade do código do aspecto. Acumular em um único ou em poucos advices os inúmeros pontos de corte representativos ao tratamento de erros geraria maior complexidade do código do aspecto. A fig. 5.8 apresenta parte do código do aspecto
É possível observar que as classes replicam a implementação das operações de tratamento de erros conforme pode ser visto nos segmentos de código da fig 5.7. Nela são mostrados os métodos de pintaFigura() e navega() declarados na classe Circulo. As classes Retangulo e Triangulo logicamente herdam estes métodos e os
implementam.
Public class Circulo extends Figura {
void pintaFigura(Graphics g, double xPos, double yPos) { try {...} catch(Exception erroPintando) {...} } void navega() { try{...} catch(Exception erroNavegando) {...} } }
Figura 5.7 – Tratamento de Exceções das Classes do Sistema
No que tange à modularização do tratamento de exceções do sistema com a utilização de aspectos, podem ser aplicadas várias abordagens diferenciadas. Dentre várias possibilidades cogitadas as duas consideradas mais coerentes são enumeradas logo abaixo:
1) A implementação de um único aspecto concreto que declararia todos os pontos de
corte sob uma abordagem centralizada;
2) A implementação de um único aspecto concreto que utilizaria os pontos de corte declarados sob uma abordagem per-class.
A primeira opção seria interessante do ponto de vista da facilidade de manutenção visto que todas os pontos de junção representativos ao tratamento de
que o conjunto de recursos exigidos pelo contexto C2. São exigidos a mais pelo contexto C1:
· Duas bibliotecas de recursos que são as bibliotecas math e util; · Trinta variáveis;
· Sete métodos.
Do ponto de vista da reutilização seria interessante se os atributos e métodos relacionados a contextos específicos fossem agregados somente quando requerido pelo contexto corrente. Sob esta proposta a próxima seção descreve a migração do aplicativo Figuras Flutuantes para uma versão orientada a aspectos. Serão descritos os aspectos que foram implementados sob a influência da convenção de classificação das RCE descrita no cap. 4. Os resultados obtidos e as conclusões finais serão descritos posteriormente.
5.3. A Versão POA do Aplicativo
Na versão POA foram mantidas as classes anteriormente descritas em sua versão OO. Entretanto foram adicionados ao sistema um total de seis aspectos onde cada um implementa uma RCE identificada no sistema.
Inicialmente será feita a identificação e modularização das responsabilidades comuns identificadas. Num segundo momento será aplicada a convenção sugerida cap. 4 para a classificação das RCE do sistema. Em paralelo seguirão as justificativas para as decisões determinaram o surgimento dos aspectos e os ganhos obtidos com a modularização das RCE.
5.3.1. A Modularização das Responsabilidades Comuns
Analisando o código do aplicativo é possível observar a existência de operações recorrentes dentro do sistema. Elas fazem referência ao tratamento de exceções, o que pode ser considerado como o exemplo mais típico de responsabilidade comum.
que são obsoletos quando a instância for inserida no contexto C2. Este conjunto de operações é descrito a seguir :
Classe Display
Importação de bibliotecas de recursos
import java.math.*; import java.util.*;
Declaração de atributos
private int displayWidth; private int displayHeight;
private static Color vermelho = Color.red; private static Color branco = Color.white; private static Color verde = Color.green; Graphics grafico; Image imagem; Registrador registrador; Figura[] listaDeFiguras; Linha linha; Implementação de métodos
public void atualizaLinhas(Graphics g, Figura rect, Figura proxRect, Color cor)
public void manipulaNavegacao(Graphics g) public void detectaColisao(Graphics g)
static boolean ocorreuColisao(Figura a, Figura b)
private void manipulaColisao(Graphics g, Figura a, Figura
Classe Registrador
Implementação de métodos
public synchronized Figura[] pegaFiguras()
Classe Figura
Importação de bibliotecas de recursos import java.math.*;
Declaração de atributos
int tempoVida = 500;
double maxXPos, minXPos, maxYPos, minYPos, maxZPos, minZPos,xPos, yPos, zPos;
int coordX, coordY, larg, alt;
boolean navegaDireita, navegaEsquerda,navegaAcima, navegaAbaixo, navegaParaFundo,
navegaParaSuperficie;
Implementação de métodos abstract void navega();
void morre(Registrador registrador)
Por meio da enumeração descrita acima pode ser observado que o conjunto de recursos exigidos para que as instâncias possam executar no contexto C1 é maior do
5.2.2.2. Herança de Operações Obsoletas ao Contexto C2
O resultado final da versão OO para o aplicativo Figuras Flutuantes foi um conjunto de classes que, criadas para serem executadas em dois contextos distintos C1 e
C2, foram implementadas de forma genérica.
Estas classes, independentemente de quaisquer dos dois contextos onde possam estar inseridas, agregam de forma permanente o conjunto de operações de deslizamento, conexão e colisão. A fig. 5.6 representa o ambiente de execução para a versão OO do aplicativo.
Figura 5.6 – Classes do Sistema sem a Modularização das RCE
D
iversas operações como importação de bibliotecas de recursos, declaração de atributos e implementação de métodos das classes são aplicáveis somente ao contexto C1 onde as operações de deslizamento, conexão e colisão são exigidas, masde métodos que são os métodos navega() e pintaFigura(), contribuindo também para o aumento de volume do código das classes conforme fig. 5.4. Outro fator negativo detectado na versão OO foi a ocorrência de referências entre as classes do sistema. A fig. 5.5 apresenta parte do código fonte da classe Display.
Ela referencia:
· Na linha 11 a classe Linha em seu método pintaLinha();
· Na classe Registrador na linha 18 em seu método pegaFiguras().
Estes métodos estão relacionados ao conjunto de operações utilizadas somente no contexto C1. Logo estas referências são obsoletas quando as instâncias estão inseridas no contexto C2 forçando a compilação constante de todo o conjunto de operações de deslizamento, colisão e conexão. Vide fig. 5.5 a seguir.
1 Import java.math.*; 2 Import java.awt.*; 3 Import java.lang.*; 4 Import java.util.*; 4
5 Public class Display extends Canvas 6 {
7 ... 8
9 public void atualizaLinhas(Graphics g, Figura rect, Figura proxRect, Color cor)
10 {
11 linha.pintaLinha(g, rect.xPos, rect.yPos, proxRect.xPos, proxRect.yPos, cor);
12 } 13
14 ... 15
16 public void manipulaNavegacao(Graphics g) 17 { 18 listaDeFiguras = registrador.pegaFiguras(); 19 ... 20 } 21 22 ... 23 }
- As instâncias quando inseridas no contexto C2 herdam o pool de operações dos
esquemas de deslizamento, conexão e colisão que para elas é obsoleta neste momento mas que são exigidas pelo contexto C1.
Nas próximas seções será feita a demonstração de segmentos de código implementados no aplicativo Figuras Flutuantes e que foram diretamente afetados pelas deficiências apontadas acima.
5.2.2.1. Entrelaçamento de Código
O entrelaçamento de código nas classes do sistema foi evidenciado de duas formas :
· Replicação constante do código referente ao tratamento de exceções(fig. 5.4);
· Dependência entre as classes do sistema pela referência no código de umas às outras.
1 Public class Circulo extends Figura 2 {
3 ... 4
5 void pintaFigura(Graphics g, double xPos, double yPos) 6 { 7 try 8 {...} 9 catch(Exception erroPintando) 10 {...} 11 } 12 13 void navega() 14 { 15 try 16 {...} 21 catch(Exception erroNavegando) 22 {...} 23 ... 24 }
Figura 5.4 - Replicação de Código para Tratamento de Exceções
O tratamento de exceções pode ser visto na implementação de várias classes do sistema. O modelo OO realmente não permite que este tipo de responsabilidade seja modularizado de uma forma natural. Por este motivo a classes Círculo, Triangulo e
b) Recuperar uma referência a um objeto Figura; c) Excluir uma referência a um objeto Figura.
· Classe SWFrame: esta classe representa a interface com o usuário, capturando os eventos que permitem a interação com o aplicativo;
· Classe Display: esta classe implementa o seguinte conjunto de responsabilidades: a) Suportar o esquema de deslizamento das figuras pela implementação do método
manipulaNavegacao();
b) Suportar o esquema de conexões das figuras pela implementação do método
atualizaLinhas();
c) Suportar o esquema de tempo de vida das figuras pela implementação dos métodos detectaColisao(), ocorreuColisao() e manipulaColisao();
d) Suportar a repintura das figuras com a invocação dos métodos de sua superclasse
Canvas.
5.2.2. As Deficiências Detectadas
A análise do código do aplicativo em sua versão OO evidenciou um conjunto de deficiências que caracterizam um menor grau de otimização de algumas classes do sistema em função dos seguintes fatores:
· Entrelaçamento de código:
- Replicação de código referente ao tratamento de exceções aumentando o
volume e a complexidade do código fonte;
- Ocorrência de referências entre as classes do sistema pela invocação de métodos
de outras classes;
É interessante frisar novamente que foram desconsideradas a aplicação de recursos mais sofisticados como a implementação de interfaces ou a aplicação de padrões de projeto que poderiam contribuir para a melhoria da qualidade da arquitetura do sistema. A arquitetura deste aplicativo, obviamente muito simples, procura apenas avaliar as possíveis contribuições do modelo orientado a aspectos no desenvolvimento de projetos de software reutilizáveis.
5.2.1. As Responsabilidades para as Classes do Sistema
Segue abaixo a descrição das responsabilidades para as classes do sistema em sua versão OO. As classes definem, além de suas responsabilidades primárias, uma série de responsabilidades secundárias que serão comentadas mais adiante.
· Classe Figura: implementa um conjunto de métodos abstratos que serão herdados por suas subclasses Circulo, Retangulo e Triangulo. São eles os método pintaFigura(), navega() e também o método morre(). É a representação abstrata de
uma figura no plano;
· Classes Circulo, Triangulo e Retangulo: as responsabilidades destas classe são: a) Encapsular atributos relacionados à sua posição atual no plano;
b) Implementar seu próprio método de pintura com a sobreposição do método abstrato pintaFigura() herdado de sua superclasse Figura;
c) Implementar sua própria forma de deslocamento no plano pela sobreposição do método navega() herdado de sua superclasse Figura;
· Classe Linha: encapsula atributos relacionadas às coordenadas de início e fim da linha no plano e também o seu desenho no plano;
· Classe Registrador: esta classe tem como responsabilidade a manutenção da estrutura que armazena as referências aos objetos Figura instanciados durante o tempo de execução. Ela implementa os métodos que possibilitam:
O contexto C1 permite a criação de um conjunto de figuras num plano e realiza algumas operações sobre estas figuras como possibilitar sua flutuação numa determinada direção, sua conexão com as demais figuras de mesmo tipo e determinar o esgotamento do seu tempo de vida. Será visto posteriormente que o contexo C2 é um contexto onde existe a exigência de um número mais reduzido de operações.
5.1.2. O Contexto C2
Neste contexto a interface do aplicativo permanece inalterada. Ela também apresenta um plano no espaço onde são criadas figuras geométricas de três tipos que podem ser círculos, retângulos ou triângulos.
As figuras continuam sendo criadas à partir da iteração do usuário com o aplicativo. A interface apresentada é a mesma e disponibiliza três botões para criação de figuras que à medida que são pressionados criam novas figuras que flutuam no plano. Cada botão é destinado à criação de um dos três tipos de figura disponíveis. Estão disponíveis um botão para criação de círculos, um botão para criação de triângulos e um botão para criação de retângulos. A interface pôde ser vista anteriormente na fig. 5.1.
A diferença entre este contexto e o contexto C1 visto anteriormente se dá ao nível das operações exigidas por cada um. Enquanto no contexto C1 as operações do esquema de deslizamento, conexão e colisão são requisitadas, no contexto C2 elas são obsoletas. Neste contexto as figuras criadas no plano são entidades estáticas, não flutuam logo não colidem. As linhas de conexão entre as figuras agora não são exigidas. As classes do sistema no entanto são as mesmas implementadas para o contexto C1 e declaram todo um conjunto de operações que permitem o seu reuso em ambos os contextos. A estrutura das classes do sistema poderá ser vista em detalhes na próxima seção.
5.2. A Versão OO do Aplicativo
Este aplicativo em sua versão puramente orientada a objetos foi concebido com a declaração de um total de oito classes. A classe abstrata Figura deriva as classes
Circulo, Triangulo e Retangulo. São declaradas ainda as classes Linha, Registrador, Display e SWFrame, conforme pode ser visto na fig. 5.3.
Figura 5.1 - Esquema de Conexões do Aplicativo
Esta exigência do contexto C1 determina o esquema de sobrevivência das figuras. A fig. 5.2 mostra o aplicativo no momento da colisão entre figuras.