This watermark does not appear in the registered version - http://www.clicktoconvert.com 106 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; } 106 This watermark does not appear in the registered version - http://www.clicktoconvert.com 105 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 Descritores Primitivos Relacionados ao Texto 105 This watermark does not appear in the registered version - http://www.clicktoconvert.com 104 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 Id) or 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 Id) or 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 Id, ...) or 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 junção baseados no controle de fluxo do programa. 104 This watermark does not appear in the registered version - http://www.clicktoconvert.com 103 TIPO Handler(Tipo) DEFINIÇÃO 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 AdviceExecution() DEFINIÇÃO 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: 1) pointcut valorInt(int x): call(Linha.*(int)) && args(x); 103 This watermark does not appear in the registered version - http://www.clicktoconvert.com 102 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(); } } 102 This watermark does not appear in the registered version - http://www.clicktoconvert.com 101 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(); } } 101 This watermark does not appear in the registered version - http://www.clicktoconvert.com 100 ANEXO 1 Modelo Aspectj para Pontos de Junção Nome Method Definição quando um método é chamado call Method quando o corpo do método está sendo executado executio n Construc quando o construtor do objeto está sendo chamado tor call Construc quando o corpo do construtor está sendo executado. Nenhum valor é retornado tor deste tipo de ponto de junção executio n Static quando um inicializador estático para a classe é executado. Nenhum valor é initiali retornado deste tipo de ponto de junção zer executio n Field para campos do tipo não constante. Campos do tipo constante não são pontos de referenc junção em função do Java os utilizar no processo de inline e Handler Quando um manipulador de exceção executa. Este tipo de ponto de junção executio requer um parâmetro que é o tipo de exceção manipulada. Nenhum valor retorna n deste tipo de ponto de junção Advice quando o corpo de um advice é executado. executio n 100 This watermark does not appear in the registered version - http://www.clicktoconvert.com 99 ANEXOS 99 This watermark does not appear in the registered version - http://www.clicktoconvert.com 98 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. 98 This watermark does not appear in the registered version - http://www.clicktoconvert.com 97 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://wwwi2.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. 97 This watermark does not appear in the registered version - http://www.clicktoconvert.com 96 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. 96 This watermark does not appear in the registered version - http://www.clicktoconvert.com 95 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. 95 This watermark does not appear in the registered version - http://www.clicktoconvert.com 94 · 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. 94 This watermark does not appear in the registered version - http://www.clicktoconvert.com 93 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: 93 This watermark does not appear in the registered version - http://www.clicktoconvert.com 92 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) 92 This watermark does not appear in the registered version - http://www.clicktoconvert.com 91 · 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 91 This watermark does not appear in the registered version - http://www.clicktoconvert.com 90 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: 90 This watermark does not appear in the registered version - http://www.clicktoconvert.com 89 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á 89 This watermark does not appear in the registered version - http://www.clicktoconvert.com 88 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 ThisJoinPoint indicará a assinatura para o ponto de junção encontrado. 88 This watermark does not appear in the registered version - http://www.clicktoconvert.com 87 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. 87 This watermark does not appear in the registered version - http://www.clicktoconvert.com 86 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. 86 This watermark does not appear in the registered version - http://www.clicktoconvert.com 85 · call(Graphics double)): Figura+.pintaFigura(Graphics, 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 85 This watermark does not appear in the registered version - http://www.clicktoconvert.com 84 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; 84 This watermark does not appear in the registered version - http://www.clicktoconvert.com 83 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 do tipo introdução. 83 This watermark does not appear in the registered version - http://www.clicktoconvert.com 82 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. 82 This watermark does not appear in the registered version - http://www.clicktoconvert.com 81 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() {...} } Figura 5.12 – O Aspecto Navegacao 81 This watermark does not appear in the registered version - http://www.clicktoconvert.com 80 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 80 This watermark does not appear in the registered version - http://www.clicktoconvert.com 79 Classe : Registrador Tabulação RCE LISTA DE CONTEXTOS 1 1 OPERAÇÕES (C1) OPERAÇÕES DE PROTEÇÃO X 2 (C2) 3 4 5 6 7 8 9 10 ... ... ... ... ... ... ... TAO 50% DO REGISTRO 2 OUTRAS OPERAÇÕES DO X X 100% REGISTRO DOS OBJETOS 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. 79 This watermark does not appear in the registered version - http://www.clicktoconvert.com 78 · 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. Classe : Display Tabulação RCE LISTA DE CONTEXTOS 1 1 2 (C2) 3 4 5 6 7 8 9 10 ... ... ... ... ... ... ... TAO OPERAÇÕES (C1) OPERAÇÕES DE X 50% OPERAÇÕES DO ESQUEMA DE X 50% TRATAMENTO DE COLISÃO 2 NAVEGAÇÃO 3 50% OPERAÇÕES DO ESQUEMA DE X CONEXÕES 4 OUTRAS OPERAÇÕES DE X X 100% MANIPULAÇÃO DOS DADOS 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. 78 This watermark does not appear in the registered version - http://www.clicktoconvert.com 77 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. Classe : Circulo, Retangulo, Tabulação RCE Triangulo LISTA DE 1 2 3 4 5 6 7 8 9 10 ... ... ... ... ... ... ... TAO CONTEXTOS (C1) (C2) OPERAÇÕES 1 OPERAÇÕES DE X X 100% PINTURA 2 OPERAÇÕES DO 50% X ESQUEMA DE NAVEGAÇÃO 3 OUTRAS X X 100% OPERAÇÕES DE MANIPULAÇÃO DOS DADOS 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: 77 This watermark does not appear in the registered version - http://www.clicktoconvert.com 76 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. 76 This watermark does not appear in the registered version - http://www.clicktoconvert.com 75 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. 75 This watermark does not appear in the registered version - http://www.clicktoconvert.com 74 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 74 This watermark does not appear in the registered version - http://www.clicktoconvert.com 73 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 trataExcecao. 73 This watermark does not appear in the registered version - http://www.clicktoconvert.com 72 É 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 72 This watermark does not appear in the registered version - http://www.clicktoconvert.com 71 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 responsabilidades comuns identificadas. Num segundo momento das 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. 71 This watermark does not appear in the registered version - http://www.clicktoconvert.com 70 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 70 This watermark does not appear in the registered version - http://www.clicktoconvert.com 69 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 Diversas 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, mas 69 This watermark does not appear in the registered version - http://www.clicktoconvert.com 68 de 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 2 3 4 4 5 6 7 8 9 Import Import Import Import java.math.*; java.awt.*; java.lang.*; java.util.*; Public class Display extends Canvas { ... 10 11 12 13 14 15 16 17 18 19 20 21 22 23 } public void atualizaLinhas(Graphics g, Figura rect, Figura proxRect, Color cor) { linha.pintaLinha(g, rect.xPos, rect.yPos, proxRect.xPos, proxRect.yPos, cor); } ... public void manipulaNavegacao(Graphics g) { listaDeFiguras = registrador.pegaFiguras(); ... } ... Figura 5.5 – Referências entre as Classes do Sistema 68 This watermark does not appear in the registered version - http://www.clicktoconvert.com 67 - 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 Retangulo replicam o código referente ao mesmo tipo de exceção no mesmo conjunto 67 This watermark does not appear in the registered version - http://www.clicktoconvert.com 66 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; · Permanente herança das operações de deslizamento, conexão e colisão: 66 This watermark does not appear in the registered version - http://www.clicktoconvert.com 65 É 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: a) Armazenar uma referência a um objeto Figura; 65 This watermark does not appear in the registered version - http://www.clicktoconvert.com 64 Figura 5.3 - Diagrama de Classes do Sistema 64 This watermark does not appear in the registered version - http://www.clicktoconvert.com 63 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. 63 This watermark does not appear in the registered version - http://www.clicktoconvert.com 62 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. Figura 5.2 - Colisão Entre Figuras 62 This watermark does not appear in the registered version - http://www.clicktoconvert.com 61 de comportamento do aplicativo para este contexto: os três tipos diferentes de figuras não se misturam no momento das conexões. Este critério determina o esquema de conexões entre as figuras que é determinado da seguinte forma: · Círculos podem se conectar somente a outros círculos, não podendo se conectar a retângulos ou triângulos; · Retângulos podem se conectar somente a outros retângulos, não podendo se conectar a círculos ou triângulos; · Triângulos podem se conectar somente a outros triângulos, não podendo se conectar a retângulos ou círculos. A fig. 5.1 mostra o aplicativo no momento em que o plano é povoado por diversos círculos, retângulos e triângulos, caracterizando o esquema de conexões do contexto C1 descrito anteriormente. O esquema de deslizamento e o esquema de conexões mencionados anteriormente são duas exigências do contexto C1 e podem ser observadas durante a execução do aplicativo. Uma terceira exigência deste contexto diz respeito ao tempo de sobrevivência das figuras. As figuras criadas neste contexto não permanecem flutuando no plano por tempo indeterminado mas sim por um tempo pré-determinado. Expirando este tempo as figuras criadas são apagadas. Eventualmente, em caso de colisão, elas podem também ser apagadas antes mesmo deste tempo expirar. À medida que figuras de tipos diferentes flutuam podem ocorrer colisões, visto que o esquema de deslizamento determina que estas se deslocam em direções diferentes. Estas colisões, quando ocorrem, determinam o fim precoce do tempo de vida das figuras envolvidas na colisão. As figuras que colidem são então apagadas do plano. 61 This watermark does not appear in the registered version - http://www.clicktoconvert.com 60 De acordo com a implementação atual, as classes do sistema podem ser inseridas em dois contextos diferenciados. O primeiro deles foi nomeado como C1 e implementa uma série de operações peculiares que serão descritas em detalhes a seguir. O segundo contexto é nomeado como C2 e é mais simplificado que o primeiro pois não requer o mesmo conjunto de operações exigidas pelo anterior. As seções a seguir apresentam a descrição das características destes dois contextos onde as classes do sistema podem ser inseridas. 5.1.1. O Contexto C1 O contexto C1 requer uma série de operações que são exigidas das classes do sistema e que não são exigidas no contexto C2 que será visto logo adiante. Este conjunto de operações é relacionado à atividades de deslizamento, conexão e colisão entre as figuras e serão descritos no decorrer desta seção. Neste contexto uma das características de comportamento do aplicativo determina que as figuras criadas flutuem em sentidos diferentes no plano. A direção na qual cada figura flutua no plano se dá em função de seu tipo, constituindo assim o esquema de deslizamento das figuras. O esquema de deslizamento é definido da seguinte forma: · Os círculos devem flutuar no sentido diagonal, avançando ao mesmo tempo nos eixos x e y; · Os triângulos devem flutuar na vertical, avançando somente no eixo y; · Os retângulos devem flutuar na horizontal, avançando somente no eixo x. Na forma como o aplicativo se apresenta, o mesmo tipo de figura pode ser criado diversas vezes. Assim, em determinado momento, o plano pode ser povoado por vários círculos, triângulos e retângulos. Outra característica do contexto C1 é que as figuras, à medida que são criadas, são conectadas por linhas. Estas linhas deslizam no plano, acompanhando o deslizamento das figuras mantendo a noção de que estas se mantêm constantemente conectadas. Esta conexão não é feita ao acaso. É feita com base em outra característica 60 This watermark does not appear in the registered version - http://www.clicktoconvert.com 59 Capítulo V Um Projeto de Software Reutilizável Utilizando POA – Uma Abordagem Otimizada da Orientação a Aspectos Como forma de avaliar a aplicação de aspectos no desenvolvimento de projetos de software reutilizáveis foi desenvolvido um aplicativo gráfico em duas versões. A primeira utilizando uma abordagem totalmente OO e a segunda sob o paradigma da orientação a aspectos. Ao longo do desenvolvimento deste capítulo é feita a descrição detalhada do aplicativo Figuras Flutuantes com os seguintes tópicos: · As características gerais de comportamento do aplicativo nos dois contextos propostos; · A estrutura do aplicativo em sua primeira versão numa abordagem puramente OO com suas classes e seus comportamentos; · A migração para o modelo orientado a aspectos visando a otimização das classes do sistema; · Conclusão a respeito dos resultados obtidos. 5.1. Características Gerais do Aplicativo Figuras Flutuantes é um aplicativo gráfico simples que 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 são criadas à partir da iteração do usuário com o aplicativo. A interface apresentada 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, conforme fig. 5.1. 59 This watermark does not appear in the registered version - http://www.clicktoconvert.com 58 contexto Cb acessoDados {controle de concorrência} {acesso a dados (gravação)} {acesso a dados (leitura)} contexto Cc {comunicação remota} { colaboração com outros objetos} { sincronismo} contexto Ca Figura 4.10 – Nova Configuração de Contextos para a Classe acessaDados No próximo capítulo é conduzida a implementação e a restruturação do aplicativo Figuras Flutuantes para uma versão POA. O critério de classificação das RCE anteriormente sugerida como convenção didática será aplicada sobre as classes do sistema e os resultados serão comentados em seguida. 58 This watermark does not appear in the registered version - http://www.clicktoconvert.com 57 corrente. Poderíamos então fatorar as operações genéricas e complexas da classe acessaDados em um conjunto de operações específicas e dirigidas a contexto. Os recursos de controle de concorrência por exemplo só seriam aplicados à classe acessaDados em contextos onde este controle fosse efetivamente exigido, evitando assim algum overhead provocado por estas operações. Se fosse necessário algum tipo de iteração com outras classes do sistema, estas operações seriam então agregadas e assim por diante. Isto contudo sem aumentar o grau de complexidade e entrelaçamento dos componentes do sistema – muitos métodos ou classes intermediárias o que gera interdependência entre módulos, diminui o grau de reusabilidade e exige um número maior de customizações manuais – o que é o efetiva contribuição da POA. É interessante observar que um ponto crítico à convenção de classificação das RCE aqui apresentada, é a ocorrência de manutenção da classe tabulada. À medida que novos contextos se abrem ou se fecham para a classe e novas operações são inseridas/removidas, a tabela RCE para a classe pode ter seus valores de TAO alterados. Este fato por certo exigirá a manutenção dos aspectos pois novas RCE surgirão ou serão removidas. Esta abordagem simplificada no entanto não considera este fato. A fig. 4.10 mostra uma nova possível configuração de contextos para a classe acessaDados. A partir desta nova configuração de contextos para a classe acessaDados, as operações de controle de concorrência passam a ser exigidas no conjunto total de contextos para a classe. Logo haveria uma importante alteração na sua Tabela RCE original pois a TAO destas operações adquiriria um novo valor, subindo de 33% para 100%. Isto justificaria, em acordo com a simples convenção aqui adotada, que esta operação fosse então modularizada em um aspecto. Entretanto estas questões não são o foco deste trabalho e como tal não serão discutidas. 57 This watermark does not appear in the registered version - http://www.clicktoconvert.com 56 Figura 4.9 – Instâncias da Classe acessaDados e as RCE Agregadas A fig. 4.9 apresenta três contextos diferenciados nomeados como C1, C2 e C3. Pode ser observado que as instâncias i1, i2 e i3 da classe acessaDados agregam apenas as RCE relativas ao seu próprio contexto resultando na seguinte configuração: · Instância i1 herda as operações de leitura e gravação implementadas na classe acessaDados e agrega também as RCE para tratamento de sincronismo implementadas no aspecto trataSincronismo caracterizando o contexto C1; · Instância i2 herda as operações de leitura e gravação implementadas na classe acessaDados e agrega também as RCE para tratamento de acesso remoto e sincronismo implementadas nos aspectos acessoRemoto e trataSincronismo caracterizando o contexto C2; · Instância i3 herda as operações de leitura e gravação implementadas na classe acessaDados e agrega também as RCE para tratamento de sincronismo implementadas no aspecto trataSincronismo caracterizando o contexto C3. Identificar e modularizar as RCE na forma de aspectos permitirá que a classe acessaDados implemente apenas as operações que representam sua estrutura primária. Desta forma, cada instância desta classe, quando necessário, agregará o apenas conjunto de operações especializadas realmente aplicáveis ao seu contexto 56 This watermark does not appear in the registered version - http://www.clicktoconvert.com 55 duas novas classes denominadas como Sub1 e Sub2 e mostra a agregação diferenciada de operações pela agregação de RCE modularizadas em aspectos. Figura 4.8 – Classe acessaDados Agregando RCE Como pode ser visto a superclasse acessaDados agrega as operações de comunicação remota modularizadas no aspecto acessoRemoto. As suas subclasses Sub1 e Sub2 no entanto agregam apenas operações de sincronismo modularizadas no aspecto trataSincronismo. Em comum as classes terão apenas as operações de leitura e gravação originalmente implementadas na superclasse acessaDados. Concluindo, as operações de acesso remoto agregadas pela superclasse não serão herdadas pelas suas subclasses. O que garante tal fato é o tecedor que implementado sob a abordagem dinâmica garante a permanência da classe original gerando a classe tecida. Esta, conforme já mencionado na seção 3.6, assume o caráter de aspin que é a classe costurada ao aspecto acessoRemoto. Estando claro o conjunto de RCE a ser agregado pela classe acessaDados em cada contexto especifico, é possível garantir que um aspecto que implemente uma determinada RCE necessária a este contexto venha a afetar a apenas determinadas instâncias desta classe. Assim, é possível aplicar a cada instância, individualmente, o conjunto de operações RCE relativas ao contexto onde a instância particular estará inserida. 55 This watermark does not appear in the registered version - http://www.clicktoconvert.com 54 métodos conecta() e transmite() nas linhas 9 e 12 são introduzidos na classe por meio do mecanismo de introduções. 1 aspect acessoRemoto 2 { 3 private socket acessaDados.skt; 4 private int acessaDados.porta; 5 6 after/before/around(): (...) 7 {...} 8 9 public void acessaDados.conecta() 10 {...} 11 12 public void acessaDados.transmite() 13 {...} 14} Figura 4.6 – Aspecto acessoRemoto O tecedor poderia então ser invocado para que o aspecto acessoRemoto fosse costurado a alguma instância da classe acessaDados ou de alguma subclasse caso alguma operação de acesso remoto fosse exigido pelo contexto corrente. A sintaxe AspectJ poderia ser aplicada nesta chamada conforme fig. 4.7. Class Principal { boolean exigeAcessoRemoto; ... public Principal() { ... if exigeAcessoRemoto then %ajweaver acessoDados.ajava acessoRemoto.ajava; acessaDados aD = new acessaDados(...) ... } ... } Figura 4.7 – Tecendo o Aspecto acessoRemoto Havendo então estruturado a classe acessaDados com base na convenção aqui adotada, suas instâncias ou as instâncias de suas subclasses poderão herdar apenas o conjunto de operações fundamentais que neste caso são as operações de leitura e gravação. As demais operações poderão ser agregadas à medida do necessário pela chamada do tecedor. A fig.4.8 apresenta a especialização da classe acessaDados em 54 This watermark does not appear in the registered version - http://www.clicktoconvert.com 53 CLASSE : acessaDados ESTRUTURA PRIMÁRIA CONJUNTO RCE Atributos : atr1, atr3, atr4. Métodos: Atributos : Atr2, atr5, atr6, atr7, atr8, atr9. Métodos: {acesso a dados (leitura)} {acesso a dados (gravação)} {colaboração} { comunicação remota} { concorrência} {sincronismo} Figura 4.4 – Identificação das RCE da Classe acessaDados Conforme pôde ser visto na fig 4.3 as operações de colaboração, comunicação remota, sincronismo e concorrência cujos TAO obtidos foram menores que 100% são desligadas da estrutura primária da classe. Serão modularizadas como aspectos conforme pode ser visto na fig. 4.5. aspecto acessoRemoto aspecto trataConcorrencia Atr5, atr6 Atr7 { operações de comunicação remota} {operações de concorrência} acessoDados atr1, atr3, atr4 {operações de acesso a dados (gravação)} {operações de acesso a dados (leitura)} aspecto trataColaboracao aspecto trataSincronismo Atr2 Atr8, atr9 {operações de colaboração} {operações de sincronismo} Figura 4.5 – Classe acessaDados Restruturada A fig. 4.6 mostra o segmento de código que poderia representar a implementação em detalhe do aspecto acessoRemoto. Ele foi implementado com base na RCE de comunicação remota acima mencionada. Os atributos skt e porta e os 53 This watermark does not appear in the registered version - http://www.clicktoconvert.com 52 Classe : acessoDados Tabulação RCE LISTA DE 1 2 3 4 5 6 7 8 9 10 (Ca) (Cb) (Cc) ... ... ... ... ... ... ... TAO CONTEXTOS OPERAÇÕES 1 COMUNICAÇÃO X 33% REMOTA 2 ACESSO À BASE DE X X X 100% X X X 100% DADOS (LEITURA) 3 ACESSO À BASE DE DADOS (GRAVAÇÃO) 4 CONTROLE DE X 33% CONCORRÊNCIA 5 SINCRONISMO X 33% 6 COLAB. COM OUTROS X 33% OBJETOS Figura 4.3 – Tabulação RCE da Classe acessaDados A tabulação RCE vista acima permitiu a determinação da TAO para classe acessaDados considerando o conjunto total de contextos onde ela possa vir a ser inserida(fig. 4.1). A seguinte situação pode ser observada : · As operações de leitura e gravação alcançaram taxa de aplicação de 100% pois são agregadas em todos os contextos que são Ca, Cb e Cc; · As operações de sincronismo, controle de concorrência, acesso remoto e colaboração alcançaram uma taxa de apenas 33% pois são exigidas apenas em contextos específicos. Consultando a tabela RCE para a classe acessaDados vista na fig 4.3 é possível então classificar o conjunto RCE da classe separando-o de sua estrutura primária. O resultado desta separação de responsabilidades para a classe pode ser visto na fig. 4.4. 52 This watermark does not appear in the registered version - http://www.clicktoconvert.com 51 implementados na classe, de modo a obter a visualização da frequência de aplicação das operações implementadas. Sugere-se que esta medição seja feita relacionando-se as operações da classe ao conjunto total de contextos onde a classe possa vir a executar. Como resultado final deve ser obtido algum valor numérico que indique a taxa de aplicação das operações durante o período de execução das instâncias da classe. Será convencionado neste trabalho que, executada a medição da taxa de aplicação das operações(TAO), somente as operações que sejam aplicáveis a todo o conjunto de contextos para a classe sejam codificadas como sua estrutura primária. As demais operações ficam caracterizadas como sendo RCE a serem modularizadas em aspectos. Este trabalho sugere que o procedimento de medição da TAO possa ser realizado com o auxílio de uma ferramenta aqui nomeada como Tabela RCE. A tabela RCE foi idealizada como uma estrutura simples cuja única função é facilitar a visualização da TAO para as operações da classe. Ela disponibiliza: · Um conjunto de linhas numeradas que discrimina o conjunto total de operações que a classe realiza; · Um conjunto de colunas numeradas que determina o conjunto total de contextos para a classe por meio da combinação do conjunto de operações necessários àquele contexto; · Uma coluna que determina o percentual de aplicação das operações com base no conjunto total dos possíveis contextos. Como exemplo será utilizda a classe acessaDados vista anteriormente na fig. 4.1. A tabulação RCE para esta classe resultará na fig. 4.3 que pode ser vista logo adiante. 51 This watermark does not appear in the registered version - http://www.clicktoconvert.com 50 Quanto à Aplicabilidade ao Conjunto Total de Contextos · Responsabilidade Comum: pode ser aplicável ao conjunto total de contextos como por exemplo o tratamento de exceções. Entretanto pode vir a ser aplicável a apenas uma parte deste conjunto como por exemplo o controle de concorrência; · RCE: é caracterizada pela aplicação a apenas parte do conjunto tal de contextos onde a classe possa vir a ser inserida. Pode ser observado pelas características enumeradas acima que as semelhanças entre as responsabilidades comuns e as RCE de fato existem o que as torna até certo ponto semelhantes. Entretanto existem duas diferenças fundamentais entre elas: · Ao contrário da responsabilidade comum, a RCE não é recorrente dentro das classes do sistema; · Ao contrário da responsabilidade comum, a RCE é sempre modularizável. A característica da RCE, conforme já mencionado, é o fato de que ela pode realmente ser modularizada na classe mas em determinados contextos ela se transformará em uma operação obsoleta e não aplicável. Este é o fato que justifica sua modularização em aspectos. 4.3. Uma Convenção para Identificação das RCE Conforme já mencionado não existem métricas definidas para a identificação das responsabilidades comuns. Tampouco este trabalho desenvolve algum formalismo científico para isso. O foco aqui é apenas a aplicação de aspectos como ferramenta de desenvolvimento de projetos de software reutilizáveis. Este capítulo formaliza uma convenção a ser seguida para que possa ser feita a identificação das responsabilidades do tipo RCE nas classes do sistema. Como procedimento padrão sugere-se que se faça uma medição sobre os métodos 50 This watermark does not appear in the registered version - http://www.clicktoconvert.com 49 Observando a fig. 4.2 é possível descrever as semelhanças e diferenças entre uma RCE e uma responsabilidade comum. Vejamos então: Quanto ao Tipo(Responsabilidade Primária/Secundária) · Responsabilidade comum: por definição ela não se encaixa sob o conceito de responsabilidade primária. Sua característica principal que é a recorrência a define sempre como uma responsabilidade secundária nas classes do sistema. Ex: o tratamento de exceções; · RCE: pode representar uma responsabilidade secundária da classe como é o caso do método trataColisao() da classe Display implementada no cap. 5 deste trabalho. Mas também pode representar uma responsabilidade primária como é o caso do método pintaFigura() implementado nas subclasses de Figura e pode ser visto em detalhes no cap. 5. Quanto à Possibilidade de Modularização · Responsabilidade comum: Pode não ser modularizável como é o caso do tratamento de exceções. Cabe observar que da mesma forma que o tratamento de exceções, que pode ser considerado como o exemplo mais típico de responabilidade comum, qualquer operação recorrente dentro das classes do sistema pode ser considerada como tal visto que não existem métricas bem definidas que determinem sua classificação; · RCE: Uma RCE é sempre modularizável pois o que a caracteriza não é a recorrência mas sim o fato de ser uma operação que se aplica a apenas parte do conjunto total de contextos onde a classe possa vir a ser inserida. Quanto à Recorrência · Responsabilidade comum: por definição ela é sempre recorrente dentro das classes do sistema; · RCE: não é recorrente. A recorrência a classificaria como responsabilidade comum. 49 This watermark does not appear in the registered version - http://www.clicktoconvert.com 48 4.2. Responsabilidade Comum x RCE O modelo orientado a aspectos oferece grande ênfase na conceituação e na modularização das responsabilidades comuns o que aliás é sua origem, embora não proponha qualquer formalismo que conduza a sua classificação. A proposta de (BOOLERT, 2000) derivou inúmeras discussões relativas a como produzir aspectos legíveis, reusáveis e mesmo propostas para representação dos aspectos em tempo de projeto entre outros. Entretanto a ênfase foi mantida sempre em torno do termo responsabilidade comum. Uma RCE não se enquadra estritamente sob o conceito da responsabilidade comum. Uma RCE é tipicamente caracterizada como uma operação que só será aplicada -seja em instâncias da própria classe ou de suas subclasses - a determinados contextos o que as torna obsoletas em outros. Assim, se for considerado o conjunto total dos possíveis contextos onde a classe acessaDados possa vir ser inserida seja ele Ca, Cb ou Cc, as RCE desta classe serão identificadas como aquelas operações que se aplicarão a apenas a um ou no máximo uma parte deste conjunto total de contextos. A análise de fatores que caracterizam as responsabilidades comuns e a sua comparação com os fatores que caracterizam as RCE resultou na fig. 4.2. Ela é um comparativo entre RCE e responsabilidades comuns procurando detectar semelhanças e diferenças entre elas. Responsabilidade Comum RCE Resp. Primária Não Sim/Não Operação Genérica Sim/Não Sim/Não Modularizável Não Sim Recorrente Sim Não Aplica-se ao Conj. Total de Sim/Não Não Contextos Figura 4.2 - Responsabilidades Comuns x RCE 48 This watermark does not appear in the registered version - http://www.clicktoconvert.com 47 · Apenas as operações de leitura e gravação são comuns aos três contextos apresentados; · Operações de comunicação remota, sincronismo e colaboração são aplicadas apenas ao contexto Ca; · Operações de controle de concorrência são aplicadas apenas ao contexto Cb. O efeito imediato é que toda instância da classe acessaDados ou qualquer instância de suas subclasses herdarão deliberadamente todo o pool de operações declarados nesta classe. Este fato determina a seguinte situação: · Instâncias inseridas no contexto Ca herdam operações aplicadas especificamente aos contextos Cb; · Instâncias inseridas no contexto Cb herdam operações aplicadas especificamente ao contextos Ca; · Instâncias inseridas no contexto Cc herdam operações aplicadas especificamente aos contextos Ca e Cb. Surgem então dois fatores que determinam um grau menor de otimização da classe acessaDados. O primeiro deles diz respeito ao tamanho do código executável visto que mesmo as operações não necessárias ao contexto serão sempre compiladas fazendo com que a instância arraste consigo vastas biblioteca de recursos, atributos e métodos que não serão utilizados. O segundo deles diz respeito à velocidade de execução que corre o risco de tornar-se reduzida. Tome-se como exemplo o contexto Cc descrito acima. Neste contexto são previstas apenas operações básicas de acesso a dados, no entanto as operações de controle de concorrência herdadas podem gerar maior overhead pois serão aplicadas sem necessidade eminente. Algum benefício poderia ser obtido se as operações aplicadas apenas a um contexto particular fossem agregadas pelas instâncias da classe somente quando estas instâncias estivessem realmente inseridas neste contexto. 47 This watermark does not appear in the registered version - http://www.clicktoconvert.com 46 contexto Cb acessoDados {controle de concorrência} {acesso a dados (gravação)} {acesso a dados (leitura)} contexto Cc {comunicação remota} { colaboração com outros objetos} { sincronismo} contexto Ca Figura 4.1 – Contextos Aplicados à Classe acessaDados Observando a classe acessaDados descrita na fig. 4.1 é possível perceber que ela implementa operações básicas de acesso a dados como leitura e gravação. Ela implementa também operações mais sofisticadas como controle de concorrência, sincronismo, transmissão remota de dados e operações de colaboração com outras classes do sistema. Logo a classe acessaDados pode ser vista como um exemplo típico de classe reusável, visto que pode ser aplicada aos três contextos diferenciados Ca, Cb e Cc com a necessidade de poucas ou talvez nenhuma customização. Entretanto, considere-se uma instância desta classe inserida em um contexto específico seja ele Ca, Cb ou Cc. Conforme pode ser visto na fig. 4.1, certas operações herdadas podem não ser necessárias num contexto particular. Todas as instâncias da classe acessaDados herdarão uma gama de operações que, havendo sido declaradas como fator determinante de reusabilidade, serão subtilizadas ou mesmo não utilizadas levando-se em conta um contexto particular. Sob este enfoque as operações implementadas na classe acessaDados se distribuem entre os três contextos apresentados conforme segue: 46 This watermark does not appear in the registered version - http://www.clicktoconvert.com 45 Para que a classe acessaDados seja eficiente e reusável nos três contextos definidos na fig. 4.1 logo adiante, ela deve implementar todas as funcionalidades requeridas por eles. Definimos assim um exemplo típico de classe reusável. Mas cabe mencionar que a complexidade da classe tem tendência a aumentar à medida em que ela avança como uma solução mais geral. Esta complexidade é pouco desejável do ponto de vista da manutenção e os recursos às vezes necessários para suportar esta generalidade muitas vezes afetam a performance de execução. Podem ser considerados como exemplos destes recursos bibliotecas de funções, estruturas de dados ou operações genéricas que provocam maior overhead do que operações especializadas. Uma alternativa para a classe acessaDados talvez fosse a modularização destas operações em classes separadas mas o primeiro efeito negativo seria o entrelaçamento de código pelo aumento de interdependência entre os módulos o que afetaria a reusabilidade. O modelo OO nos deixa então duas escolhas a serem feitas: · Uma classe reusável que implemente todas as operações e seja independente porém mais complexa; · Uma classe menos complexa mas que seja dependente de outras classes que implementem partes de suas operações. O primeiro ponto a considerar é que a dependência entre módulos é algo difícil de gerenciar. Logo pensar nesta classe como um componente independente dentro do sistema é algo sem dúvida muito vantajoso. A fig 4.1 permite visualizar a posição da classe acessaDados ente os três supostos contextos Ca, Cb e Cc. 45 This watermark does not appear in the registered version - http://www.clicktoconvert.com 44 atributos e métodos declarados por uma classe. Como resultado implica que todas as instâncias de uma classe e também todas as instâncias de suas subclasses herdarão todo um conjunto de operações de forma deliberada. O modelo OO não prevê mecanismos que permitam a distinção entre as operações que realmente vão ser utilizadas por uma instância de classe em um contexto particular daquilo que pode ser considerado como uma ‘herança inútil’. O termo herança inútil pode ser entendido como uma referência a um atributo ou um método declarado na classe e que foi herdado pela sua instância, mas não se aplica ao contexto onde esta instância se encontra inserida num determinado momento. O mecanismo de herança representa algo de muito vantajoso visto que não precisamos gastar tempo refazendo operações que já foram codificadas uma vez. São obtidas então modularidade, reusabilidade e toda a gama de vantagens oferecidas pelo modelo OO. Entretanto as RCE estão relacionadas à parte menos vantajosa do mecanismo de herança que é a sua efetividade nos termos descritos no parágrafo anterior. Como forma de exemplificar tome-se então uma classe de acesso a dados chamada acessaDados. Esta classe foi projetada para ser executada em três contextos diferenciados aqui nomeados como Ca, Cb e Cc. Cada um destes contextos requer da classe um determinado conjunto de funcionalidades. O conjunto total de operações requeridas pelos três contextos são : · Acesso a dados (leitura e gravação); · Controle de concorrência; · Comunicação remota; · Sincronismo; · Operações de colaboração com outros objetos do sistema. 44 This watermark does not appear in the registered version - http://www.clicktoconvert.com 43 Capítulo IV Desenvolvimento de Projetos de Software Reutilizáveis – Uma Visão Diferenciada do Modelo Orientado a Aspectos O modelo de aspectos permite de fato a modularização das responsabilidades comuns de uma forma natural, eliminando a replicação de código que é seu maior objetivo. A contribuição deste trabalho no entanto está em lançar uma visão diferenciada sobre a POA, objetivando a aplicação do modelo orientado a aspectos no desenvolvimento de projetos de software reutilizáveis. Desta forma, ao invés de aplicar a POA apenas como um mero recurso que permite modularização das responsabilidades comuns, aplica-la também como uma ferramenta que possa ser empregada na fatoração da classe em um conjunto de RCE visando aumento do seu grau de reusabilidade. O que se espera como resultado final são classes que mantenham o seu grau de generalidade pela agregação de operações específicas para um determinado contexto na forma de aspectos. 4.1. O Conceito de RCE O conceito de responsabilidade comum se justifica à partir de uma característica do modelo OO: as propriedades recorrentes dentro do sistema e que extrapolam as fronteiras da classe. O que caracteriza as RCE não é a recorrência dentro das classes do sistema, mas sim o fato de que são aplicáveis a apenas uma parte do conjunto total de contextos onde a classe possa vir a ser inserida. Este fato as torna obsoletas em outros contextos. As RCE justificam-se a partir de uma característica intrínseca do modelo OO: o mecanismo de herança. Este mecanismo é efetivo, ou seja, é aplicado a todos os 43 This watermark does not appear in the registered version - http://www.clicktoconvert.com 42 Este tratará da sincronização e então invocará o método original m1 na classe C. Caso esta mensagem não venha a requerer sincronismo mecanismo de lookup fará diretamente a invocação do método original m1 em C. O diagrama de estados para o exemplo acima é dado por (BOOLERT, 2000) e está representado na figura 3.17. Figura 3.17 – Diagrama de Estados da Classe Tecida C’ - Fonte (BOOLERT, 2000) Este capítulo finaliza a apresentação da implementação AspectJ para o modelo de aspectos. A próxima seção apresentará a implementação do aplicativo Figuras Flutuantes, desenvolvido em duas versões. Uma primeira numa abordagem totalmente OO e uma segunda versão agora com a migração para o modelo de aspectos com a modularização das RCE. 42 This watermark does not appear in the registered version - http://www.clicktoconvert.com 41 domínio. Na terminologia POA as classes sob o domínio do aspecto é o conjunto de classes que o aspecto afeta. Uma diferença marcante entre as abordagens estática e dinâmica é que enquanto a primeira afeta a classe, a segunda afeta somente determinadas instâncias da classe (HIGHLEY et al, 2000). Conforme mencionado anteriormente na abordagem dinâmica o aspecto é tratado de forma equivalente à classe, visto que é instanciado sob a forma de aspin. A cada aspin é adicionado um novo e importante membro: um vetor onde constam todos os objetos sob seu domínio. A estes objetos do mesmo modo é adicionado um vetor onde constam todos os aspins que têm o objeto sob seu domínio. A fig. 3.16 é fornecida por (BOOLERT, 2000) demonstra de forma sintética o trabalho do tecedor de aspectos. Ela apresenta o surgimento da classe tecida, identificada como C’. O método identificado como m1 é o método tecido gerado a partir da costura do aspecto a . Figura 3.16 – Classe e Método Tecidos – Fonte (BOOLERT, 2000) A fig. 3.16 exemplifica a abordagem de classes tecidas supondo um aspecto de sincronismo envolvendo as classes C e C’ e seus métodos. Quando a classe tecida C’ receber uma mensagem destinada ao método costurado m1’ e esta mensagem requerer sincronismo o mecanismo de lookup invocará o método tecido. 41 This watermark does not appear in the registered version - http://www.clicktoconvert.com 40 Uma Segunda forma de tecimento estático pode ser visto na fig. 3.15 e é chamado de Composição Explícita. Neste método o processo de inline não é adotado. Ao invés disto a classe afetada pelo aspecto recebe um atributo que o referencia. Esta é uma forma estática de se trabalhar com os aspins, pois o novo membro da classe é introduzido em tempo de compilação e referencia o aspin, que é uma instância de aspecto (HIGHLEY et al, 2000). APONTADOR PARA O ASPIN ASPIN CLASSE ORIGINAL Figura 3.15 – Tecimento Estático por Composição Explícita A abordagem dinâmica por sua vez não altera o código original das classes do sistema. Ao contrário, utiliza o mecanismo de herança para especializar as classes existentes com as estruturas especializadas dos aspectos (BOOLERT, 1999, HIGHLEY et al, 2000). De forma resumida o procedimento é o seguinte: suponhamos que um aspecto Asp afeta métodos de uma classe Ca. O tecedor declara uma nova classe como subclasse desta designada classe tecida (Cavw). Na subclasse Cavw são sobrescritos os métodos afetados pelo aspecto Asp, substituindo-os pelos chamados métodos tecidos. No momento da execução quando uma mensagem é enviada à classe Ca, esta classe é normalmente localizada e o método envolvido na mensagem é executado. O tecedor então procura pela classe tecida Cavw e executa o método tecido correspondente. Desta forma a classe Ca apresentará, além de seu comportamento original, o comportamento adicionado pelo aspecto Asp. No mecanismo de tecimento dinâmico a ligação do aspin com a classe é feita em tempo de compilação. O aspecto, por meio dos métodos específicos addObject() e removeObject() adiciona ou remove um determinado objeto de seu 40 This watermark does not appear in the registered version - http://www.clicktoconvert.com 39 Em um programa desenvolvido sob a abordagem POA, as classes representam apenas a estrutura primária do sistema. Os aspectos por sua vez assumem o papel de estruturas funcionais especializadas que determinam as responsabilidades comuns do sistema. Um aspecto geralmente refere-se a pontos específicos do fluxo de execução. Estes pontos são os chamados pontos de junção e podem referir-se a um método, um construtor, atribuição de valores a variáveis e outros. Na abordagem estática o tecedor costura novos atributos e métodos às classes do sistema. O aspecto pode ser meramente compilado com a classe, introduzindo nesta novos atributos, métodos e também advices. Este processo se dá em tempo de compilação e o resultado é que todo objeto desta classe assumirá as alterações provocadas pelo aspecto. O aspecto sofre um processo de inline dentro da classe. O resultado gerado à partir da tecimento da classe ao aspecto é definido na literatura como aspin ou classe costurada (BOOLERT, 1999, HIGHLEY et al, 2000). A abordagem estática pode ser vista na fig. 3.14 e impede que o nível adicional de abstração introduzido no sistema pelos aspectos tenha impacto negativo no que diz respeito ao quesito performance. Entretanto como ponto negativo a este processo de inline torna-se difícil distinguir os aspectos da estrutura original do programa. Nada muito significativo até o momento em que se tenta manipular o ‘código de aspectos’ dinamicamente. Sob a abordagem estática esta tarefa pode tornar-se muito difícil ou mesmo impossível (BOOLERT, 2000). CLASSE ORIGINAL + ASPECTO = CLASSE CLASSE ‘COSTURADA’ Figura 3.14 – Tecimento Estático Aplicando inline 39 This watermark does not appear in the registered version - http://www.clicktoconvert.com 38 [<private> <public> <abstract>] aspect nomeAspecto { [<declaração de atributos Java ordinários>] [<declaração de atributos introduzidos>] [<especifcação dos pontos de corte nomeados>] [<especificação dos advices >] [<implementação de métodos Java ordinários>] [<implementação de métodos introduzidos>] } Figura 3.13 – Anatomia do Aspecto Um aspecto é uma unidade similar a uma classe pois é declarado de forma semelhante a ela. Declara atributos, implementa métodos e possui instâncias. O aspecto, entretanto, apresenta um recurso a mais que é o advice (HIGHLEY et al, 2000). E o que seria uma instância de aspecto. Elas são denominadas sob o termo aspin e estão presentes na abordagem de tecimento dinâmico a ser vista com maiores detalhes na próxima seção. O AspectJ trata objetos e aspins como entidades equivalentes considerando que o aspin tem uma característica adicional: ele pode eventualmente encapsular advices. Logo, um aspin sem advices é simplesmente uma classe. De forma similar a um objeto, cada aspin tem o conjunto de atributos e métodos declarados em seu aspecto correspondente mas cada aspin possui seu próprio conjunto de valores para estes atributos. 3.6. Tecedor de Aspectos e Classes – Aspect Weaver Vários trabalhos definem como centro das discussões o mecanismo de tecimento de aspectos e classes. São comentadas as formas estática e dinâmica de trabalho do tecedor e são relatadas vantagens e desvantagens nas duas abordagens (BOOLERT, 1999, HIGHLEY et al, 2000, SUZUKI & YAMAMOTO, 1999). 38 This watermark does not appear in the registered version - http://www.clicktoconvert.com 37 Este valor fica armazenado na variável num declarada na linha linha 3. Este valor é então analisado e sendo maior que zero o fluxo de execução segue normalmente caso contrário uma mensagem de aviso é emitida (linhas 4 a 7). No cap. 5 pode ser observada a implementação do aspecto reduzTempoDeVida. Este aspecto implementa um advice do tipo around() que altera o contexto de execução do objeto afetado. 3.4.1. A Ordem de Precedência dos Advices Não é atípica a situação em que, dada uma aplicação, diversos advices façam referência ao mesmo conjunto de pontos de junção. Para estes casos o AspectJ estabelece algumas regras que definem a ordem de precedência deste conjunto de advices. Dados dois aspectos concretos A e B que declaram respectivamente os advices a1 a2 referentes a um mesmo ponto de junção pj as regras são descritas a seguir: 1) se o aspecto A tem a precedência explícita sobre o aspecto B feita com o uso da declaração precedence, então o advice a1 será executado antes do advice a2; 2) se o aspecto B é um subaspecto de A, então o advice a1 tem precedência sobre o aspecto a2; 3) se B não for subaspecto de A e a declaração precedence não for aplicada a ordem de precedência é então desconhecida. 3.5. Aspectos Conhecendo os modelos de ponto de junção, ponto de corte, advices e introduções oferecidos pelo AspectJ é possível então tratar especificamente da implementação dos aspectos. Um aspecto em AspectJ é, conforme especifica o conceito, uma unidade funcional que modulariza as responsabilidades comuns da aplicação. Um aspecto em AspectJ pode conter apenas advices, apenas introduções, ambos ou mesmo nenhum destes elementos, podendo conter apenas declarações ordinárias da linguagem Java. A declaração geral pode ser vista na fig 3.13. 37 This watermark does not appear in the registered version - http://www.clicktoconvert.com 36 3.4. Os Advices O AspectJ permite a implementação das responsabilidades comuns sob duas formas distintas (KICKZALES et al, 2001). A primeira delas é descrita como aditiva pois permite que algum código adicional seja executado a partir do momento em que um ponto de corte é encontrado. Esta abordagem determina a natureza dinâmica do AspectJ, visto que acontece em tempo de execução. A segunda forma é pela inclusão de novos membros às classes do sistema e caracteriza a natureza estática do AspectJ, visto que acontece em tempo de compilação através do mecanismo de introduções. A diferença reside no fato de que enquanto os advices before() ou after() podem apenas receber valores de retorno do contexto de execução do ponto de junção, o advice around() pode introduzir novos valores neste contexto de execução ou mesmo alterar o fluxo de execução deste contexto (KICKZALES et al, 2001). A fig 3.12 apresenta uma situação onde a execução dos advices é condicionada ao valor de retorno produzido pela chamada do ponto de junção. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void around(Ponto pt) : target(pt) && call(void setX(int)) { int num = pt.getX(); if num = 0 then System.out.println(“Valor inválido”) else proceed; } void around(Linha ln) : target(ln) && call(void setP1(Ponto)) { ponto pt = ln.getP2(); if pt = null then System.out.println(“Valor inválido”) else proceed; } Figura 3.12 – Advice around() No primeiro advice, implementado entre as linhas 1 e 8, a primitiva target garante uma referência ao objeto que recebeu a chamada do método especificado como ponto de junção pela primitiva call (linha 1). Esta referência fica armazenada na variável pt e é utilizada para ler um valor do contexto de execução do objeto. 36 This watermark does not appear in the registered version - http://www.clicktoconvert.com 35 · private boolean Ponto.cor = clred – esta declaração introduz na classe Ponto um campo privado chamado cor e o inicializa com o valor clred. Pelo fato deste campo ter sido declarado como private apenas o código definido no aspecto pode ter acesso a ele; · public int Ponto.getX() { return x; } – esta declaração introduz um método chamado getX() na classe Ponto. Este método retorna um inteiro e não recebe qualquer argumento. Pelo fato de ter sido declarado como public qualquer código pode acessá-lo; · public Ponto.new(int x, int y) {this.x = x; this.y = y;} – esta declaração introduz um construtor na classe Ponto. Este construtor possui como pode ser observado dois argumentos do tipo inteiro e seu corpo é this.x = x; this.y = y. Um exemplo completo pode ser observado na fig. 3.11. Ele apresenta a especificação do aspecto monitoraY. Estes aspecto introduz na classe Ponto os seguintes membros: · Linha 3 : um atributo inteiro privado yAntigo; · Linhas 9 a 11 : um método cuja assinatura é somaNovoY(inty); · Linhas 12 a 14 : um método cuja assinatura é guardaYAntigo(inty). 1 2 3 Aspect monitoraY { private int Ponto.yAntigo; 4 after(Ponto p) returning(int y): target(p) && (call(int getY(int))) { p.guardaYAntigo(y); p.somaNovoY(y) } 5 6 7 8 9 10 11 12 13 14 15 } public void Ponto.somaNovoY(int y) { y ++; } public void Ponto.guardaYAntigo(int y) { yAntigo = y; } Figura 3.11 – Introduzindo Novos Membros na Classe Ponto 35 This watermark does not appear in the registered version - http://www.clicktoconvert.com 34 Neste caso um objeto do tipo Ponto e um valor inteiro estarão disponíveis quando os pontos de junção forem encontrados. Se forem observados os eventos definidos como pontos de junção é constatado que o objeto Ponto retornado é o objeto que recebe a invocação do método e que o valor inteiro é o argumento que consta na assinatura do método invocado. Entretanto, há uma regra geral a ser seguida que é a seguinte: quando os eventos definidos como pontos de junção acontecem, todos os parâmetros do ponto de corte devem ser vinculados a algum valor. Deste modo, a definição mostrada na fig 3.10 resultará em erro de compilação. Pointcut capturaPontos(Ponto p1, Ponto p2): (target(p1) && call(void setX(int))) || (target(p2) && call(void setY(int))); Figura 3.10 – Regra Geral de Parametrização Aqui o ponto de corte define como pontos de junção os seguintes eventos: um método setX(int) invocado em um objeto Ponto qualquer ou um método setY(int) invocado de um outro objeto Ponto qualquer. O que ocorre aqui é o seguinte: na definição de parâmetros do ponto de corte há a tentativa de obter o retorno de dois objetos Ponto diferentes (p1 e p2) ao mesmo tempo. Supondo que o ponto de junção setX(int) seja encontrado em um objeto Ponto qualquer, haverá então disponível na variável p1 uma referência ao objeto origem do evento. Não haverá outro objeto Ponto para vincular ao parâmetro p2 do ponto de corte. Neste caso o parâmetro p2 é dito não vinculado gerando assim um erro de compilação. 3.3. Introduções As introduções (anexo 3) permitem introduzir novos membros nas classes do sistema, bem como alterar a hierarquia das classes por meio de declarações especiais. As classes Ponto e Linha apresentadas anteriormente na fig. 2.1 podem ser utilizadas para descrever algumas construções do tipo introdução : 34 This watermark does not appear in the registered version - http://www.clicktoconvert.com 33 Vejamos outro exemplo que nos permite avaliar a flexibilidade do modelo de parametrização de pontos de corte oferecido pelo AspectJ. Considere-se o ponto de corte nomeado que pode ser visto na fig. 3.7. pointcut testaIgualdade(Ponto p): target(Ponto) && args(p) && call(boolean equals(Object)); Figura 3.7 – Ponto de Corte com Retorno do Objeto Passado como Parâmetro Similarmente ao anterior, este ponto de corte captura também um parâmetro do tipo Ponto quando os eventos relacionados aos pontos de junção ocorrerem. Mas neste caso, se for observado o lado direito da declaração, constatamos que o objeto nomeado no parâmetro da chamada da função equals() não é o objeto Ponto que recebe a chamada. Ele é um outro objeto passado como parâmetro à função. Eventualmente pode-se querer ter acesso a ambos os objetos. O ponto de corte deverá ser declarado da forma mostrada na fig. 3.8. Pointcut testaIgualdade(Ponto p1, Ponto p2): target(p1) && args(p2) && call(boolean equals(Object)); Figura 3.8 – Ponto de Corte com Retorno de Dois Objetos Levando em conta a flexibilidade do modelo, pode-se voltar ao ponto de corte chamado atribuidor definido inicialmente e considerar uma variação na sua construção de modo a obter como retorno, além do objeto onde o ponto de junção foi encontrado, um valor inteiro referente ao parâmetro recebido por este ponto de junção. Vejamos então a fig. 3.9. Pointcut atribuidor(Point p, int newval): target(p) && args(newval) && (call(void setX(int)) || call(void setY(int))); Figura 3.9 – Ponto de Corte com Retorno de Um Objeto e Um Valor Inteiro 33 This watermark does not appear in the registered version - http://www.clicktoconvert.com 32 sofrer o processo de overloading. Logo, declarar dois pontos de corte com o mesmo nome na mesma classe ou aspecto acarreta um erro. 3.2.2. Parametrização dos Pontos de Corte Os aspectos podem ter acesso a partes privadas das classes. Este acesso, contudo, não compromete o encapsulamento esperado entre as diferentes classes do sistema (VOELTER, 2000). Os pontos de corte podem de alguma forma expor partes do contexto de execução dos pontos de junção. Esta exposição se dá através de seu modelo de parametrização. Este modelo permite que algum valor seja retornado ao advice quando o ponto de junção é encontrado e o ponto de corte é executado. Considere-se o seguinte ponto de corte que será nomeado como atribuidor e pode ser visto na fig. 3.5. pointcut atribuidor(): target(Ponto) && (call(void setX(int)) || call(void setY(int))); Figura 3.5 – Ponto de Corte sem Retorno de Valor O lado direito da declaração determina como pontos de junção as chamadas aos métodos setX(int) ou setY(int). A primitiva target garante que sejam executadas em alguma instância da classe Ponto. O lado esquerdo da declaração define um ponto de corte de nome atribuidor e nenhum retorno é esperado. Considere-se agora a seguinte declaração para o mesmo ponto de corte a ser dada na fig 3.6. pointcut atribuidor(Ponto p): target(p) && (call(void setX(int)) || call(void setY(int))); Figura 3.6 – Ponto de Corte com Retorno do Objeto Chamado Esta versão define exatamente os mesmos pontos de junção mas o ponto de corte captura um parâmetro do tipo Ponto. Como efeito prático, esta declaração permite que quando os eventos relativos aos pontos de junção ocorrerem, uma referência ao objeto Ponto que originou o evento estará disponível na variável p. A primitiva target garante que o objeto que originou o evento seja realmente um objeto da classe Ponto. 32 This watermark does not appear in the registered version - http://www.clicktoconvert.com 31 membro comum da classe. Desta forma, pode também assumir os modificadores public ou private. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 abstract aspect operacoesEmX { abstract pointcut escreveuX(); abstract pointcut leuX(); } aspect lerX extends operacoesEmX { pointcut leuX(): call(public Ponto.getX()); after(): leuX() { System.out.println(“R”); } } aspect escreverX extends operacoesEmX { pointcut escreveuX(): call(public Ponto.setX(int)); after(): escreveuX() { System.out.println(“W”); } } Figura 3.4 – Pontos de Corte Abstratos Seguindo este raciocínio os pontos de corte, da mesma forma que os métodos, podem ser do tipo final ou abstract. Para eles vale a mesma regra aplicada aos métodos ou seja, pontos de corte abstratos só podem ser declarados em aspectos abstratos. Quando necessário eles podem ser estendidos e implementados do mesmo modo que um método de uma classe abstrata. A fig. 3.4 mostra o aspecto abstrato operacoesEmX implementado entre as linhas 1 e 5. Ele declara dois pontos de corte abstratos nomeados como escreveuX() e leuX() implementados nas linhas 3 e 4. O aspectos concretos declarados nas linhas 7 e 16 estendem o aspecto abstrato operacoesEmX e sobrescrevem os pontos de corte abstratos especificando agora o conjunto de pontos de junção desejado (linhas 9 e 18). Para complementar podem também ser definidos como final. Entretanto há um ponto importante a ser considerado. Apesar dos pontos de corte poderem ser declarados e estendidos em sub-aspectos como se fossem métodos eles não podem 31 This watermark does not appear in the registered version - http://www.clicktoconvert.com 30 Eles podem ser separados em grupos que de certa forma determinam o gênero destes pontos de junção. Estes descritores são aplicados para selecionar pontos de junção de um determinado tipo – chamada de método, chamada de construtor, execução de método, etc (LOPES, 2002). O modelo de pontos de corte do AspectJ pode ser visto no anexo 2 onde são apresentados os descritores primitivos seguidos de explicações e exemplos. 3.2.1. A Nomeação dos Pontos de Corte Existem outras questões a serem consideradas no que diz respeito ao modelo de pontos de corte. O AspectJ define no seu modelo de pontos de corte que estes possam ser declarados de forma anônima ou nomeada. Um ponto de corte anônimo é a simples composição dos pontos de junção diretamente associados ao advice sem qualquer identificador que possa lhe atribuir um nome único. Quando ao ponto de corte é submetido um identificador, diz-se que este ponto de corte é do tipo nomeado. O primeiro efeito prático em se nomear um ponto de corte é relativo à sua reusabilidade, conforme pode ser visto na fig. 3.3. 1 2 3 4 5 Class Ponto { //**Outras declarações Java public pointcut escreveuX(): call(public setX(int); } 6 7 8 9 10 11 12 aspect exemplo { after(): escreveuX() { System.out.println(“W”); } } ponto de corte nomeado Figura 3.3 – Ponto de Corte Nomeado Declarado como Membro de Classe O AspectJ permite que um ponto de corte seja declarado tanto em um aspecto como em uma classe ordinária. Neste último caso ele é tratado como um 30 This watermark does not appear in the registered version - http://www.clicktoconvert.com 29 nível de projeto, ou seja, o código entrelaçado (BLAIR & BLAIR, 1998). O weaving será apresentado com maiores detalhes ao longo deste trabalho. 3.1. O Modelo de Pontos de Junção Conforme já mencionado o conceito de ponto de junção diz respeito a pontos dentro da aplicação onde uma determinada ação é realizada. Eles dizem respeito então a algum tipo de evento que pode ocorrer em algum ponto da aplicação em algum momento. O AspectJ implementa o seu modelo de pontos de junção com base num conjunto de onze eventos distintos. Um dos eventos mais comuns do conjunto de pontos de junção do AspectJ é a chamada de método. A lista completa dos eventos passíveis de constituírem pontos de junção são mostrados neste trabalho (anexo 1). 3.2. O Modelo de Pontos de Corte Conforme já citado um ponto de corte é uma estrutura capaz de agrupar um ou mais pontos de junção, determinando os termos da execução do advice. No AspectJ a estrutura de um ponto de corte é definida por duas declarações separadas pelo caractere ‘:’. A parte à esquerda de ‘:’ determina a nomeação do ponto de corte e a parte à direita especifica os eventos que relacionam os pontos de junção, como pode ser observado no segmento de código da fig. 3.2. 1-<pointcut Exemplo> : 2-<Ponto.setX(int)> || 3<Linha.setP1(Ponto)> { 4-<System.out.println(“W”);> } 1) nome 4)corpo 2,3) pontos de junção Figura 3.2 – Ponto de Corte AspectJ O modelo de pontos de corte do AspectJ fornece um conjunto de 26 descritores de tipo primitivos, os chamados pointcut descriptors. Estes descritores de tipo têm como objetivo determinar o critério de seleção para os pontos de junção definidos no ponto de corte. 29 This watermark does not appear in the registered version - http://www.clicktoconvert.com 28 Orientado a aplicação AML Orientado a Domínio RG Orientado a responsabilidade Propósito geral RIDL COOL talk AspectJ Figura 3.1 – AspectJ como Solução de Propósito Geral O AspectJ é uma extensão da linguagem de programação Java e tal característica foi planejada com o intuito de atingir a comunidade de programadores visto que o Java é largamente utilizado (KICKZALES et al, 2001). Esta decisão levou ao desenvolvimento de quatro diretrizes que caracterizam a ferramenta da seguinte forma: · Compatibilidade de código executável – um programa Java é um programa AspectJ compatível; · Compatibilidade de plataforma - todo programa AspectJ pode ser executado em uma JVM; · Compatibilidade de ferramentas – uma IDE que suporta a programação Java suporta também a programação orientada a aspectos; · Compatibilidade de declarações – a programação com AspectJ deve ser compatível com a forma de construir programas em Java. O compilador do AspectJ apresenta uma fase preliminar de tecimento ou weaving. Em uma primeira fase da compilação ele resolve de forma não ambígua as capacidades comuns entre classes e aspectos. Em uma segunda fase o compilador tradicional Java é invocado para resolver as declarações Java ordinárias. O resultado do processo de tecimento no nível do código compilado é aquilo que se tenta evitar no 28 This watermark does not appear in the registered version - http://www.clicktoconvert.com 27 · Nível de implementação – deve oferecer uma organização adequada de modo que as responsabilidades possam ser isoladas umas das outras (LOPES, 2002). O AspectJ possui um conjunto de diferenças significantes diante das suas predecessoras que são as seguintes: · O conceito da coordenação como elemento de primeira ordem na linguagem foi deixado de lado. AspectJ declara aspectos e estes podem contemplar questões relativas à coordenação; · Diferentemente de DJ, uma de suas predecessoras, o AspectJ oferece manipuladores para instâncias de aspectos através da operação AspectOf(). Entretanto existe também a preservação de características significantes diante das suas predecessoras que são as seguintes: · Conceito de ponto de corte - já havia sido identificado nas linguagens DJ e RG, mas estas apresentavam apenas pontos de corte para envio e recepção de mensagens pelos objetos do sistema. O AspectJ teve seu conjunto de pontos de corte largamente expandido; · Referências temporais - as declarações before/after oferecidas pela linguagem DJ foram mantidas; · Introduções – o recurso introdução foi apresentado inicialmente pelas linguagens COOL e CLOS e foram mantidas pelo AspectJ. A fig. 3.1 posiciona o AspectJ dentre algumas soluções desenvolvidas sob o enfoque da modularização das responsabilidades comuns. O AspectJ pode ser considerado como uma solução de propósito geral enquanto suas predecessoras são posicionadas como soluções orientadas a domínio. Dentre elas pode-se mencionar linguagens como RIDL para transmissão de dados, COOL para sincronização, RG para processamento de imagem e AML para processamento de matrizes) (LOPES & KICKZALES, 1998). 27 This watermark does not appear in the registered version - http://www.clicktoconvert.com 26 Capítulo III Projeto Orientado a Aspectos com Aspectj A abordagem POA é um conceito e não está restrito a uma linguagem ou paradigma de programação. Pode ser aplicado em auxílio às deficiências de qualquer linguagem(procedural, OO ou funcional) que use decomposição hierárquica. Neste capítulo será visto especificamente o AspectJ. O AspectJ é uma ferramenta desenvolvida pela Xerox PARC aplicada especificamente sobre Java. Os elementos de linguagem do AspectJ são descritos aqui com base nas definições de Gregor Kickzales (KICKZALES, 2001), pesquisador da Xerox PARC e um dos idealizadores da POA. São abordados aqui de forma sucinta o modelo AspectJ para pontos de junção, pontos de corte, advices e aspectos bem como seu funcionamento e pequenos exemplos explicativos. O AspectJ é uma linguagem de propósito geral onde podem ser especificados aspectos relativos a aplicações distribuídas e não distribuídas, controle de concorrência, protocolos inter-classe e otimizações. Permite que os aspectos sejam facilmente ligados e desligados da aplicação, bastando para isso invocar o weaver (LOPES & KICKZALES, 1998). Se fosse necessário tecer o aspecto afetaPontoELinha visto na fig. 2.6 à classe Ponto a sintaxe a ser aplicada seria: % ajweaver Ponto.ajava Linha.ajava afetaPontoELinha.ajava. O AspectJ atinge as duas premissas básicas que permitem a modularização das responsabilidades comuns. Estas duas premissas atingem os níveis conceitual e de programação onde: · Nível conceitual – deve oferecer um nível de abstração suficiente de modo que cada responsabilidade comum seja definida como um conceito individual; 26 This watermark does not appear in the registered version - http://www.clicktoconvert.com 25 · a primitiva target determina que os pontos de junção quando encontrados sejam provenientes de um objeto da classe Linha; · chamadas de métodos com a mesma assinatura dos pontos de junção mas provenientes especificamente de outra classe que não a classe Linha são desconsiderados. O operador OU, representado pela palavra reservada || faz a junção dos dois segmentos acima determinando que o advice será executado seja encontrando pontos de junção do primeiro ou do segundo segmento. O advice do aspecto afetaLinha faz uso das mesmas primitivas e pode ser analisado da mesma forma. Os elementos apresentados neste capítulo determinam a base do modelo orientado a aspectos. Será visto na próxima seção o implementação AspectJ para programação orientada a aspectos e a forma pela qual os aspectos, advices, pontos de junção e pontos de corte são tratados. 25 This watermark does not appear in the registered version - http://www.clicktoconvert.com 24 Figura 2.10 - Relação Aspecto-Classe O advice implementado no aspecto afetaPontoELinha combina as primitivas target e call resultando em um advice que pode ser analisado mais facilmente se dividido em dois segmentos : 1) (target(Ponto) && call(setX(int) || setY(int)) ) · a primitiva call determina como pontos de junção chamadas aos métodos setX() ou setY(); · a primitiva target determina que os pontos de junção quando encontrados sejam provenientes especificamente de um objeto da classe Ponto; · chamadas de métodos com a mesma assinatura dos pontos de junção mas provenientes de outra classe que não a classe Ponto são desconsiderados. 2) (target(Linha) && call(setP1(Ponto) || setP2(Ponto)) ) · a primitiva call determina como pontos de junção chamadas aos métodos setP1() ou setP2() ; 24 This watermark does not appear in the registered version - http://www.clicktoconvert.com 23 execução. O aspecto, por sua vez, apresenta um relacionamento dinâmico com as classes do sistema. Conforme já mencionado um aspecto é um segmento de código que representa uma unidade funcional recorrente dentro do sistema. Ele modulariza as responsabilidades comuns e pode referenciar diversas classes ao mesmo tempo. Ambos os advices implementados na fig. 2.9 referenciam apenas pontos de junção da classe Ponto (linhas 3 e 8). Já os advices implementados no aspecto afetaPontoELinha (linhas 15 e 20) declaram como pontos de junção os métodos setX() e setY() da classe Ponto mas também os métodos setP1() e setP2() da classe Linha. 1 2 3 4 5 6 7 8 9 10 11 12 aspect afetaPonto { before() : Ponto.setX(int) || Ponto.setY(int) { System.out.println(“W”); } after() : Ponto.getX() || Ponto.getY() { System.out.println(“R”); } } 13 aspect afetaPontoELinha 14 { 15 before() : Ponto.setX(int) || Ponto.setY(int) || 16 Linha.setP1(Ponto) || Linha.setP2(Ponto) 17 { 18 System.out.println(“W”); 19 } 20 before() : Ponto.getX() || Ponto.getY() || 21 Linha.getP1() || Linha.getP2() 22 { 23 System.out.println(“R”); 24 } 25 } Figura 2.9 –Aspecto Referenciando Duas Classes O relacionamento aspecto-classe pode ser definido em acordo com a fig. 2.10. Ela apresenta uma visão conceitual deste relacionamento com base no aspecto implementado na fig. 2.9. O campo de influência do aspecto sobre a classe se mostra à medida que os advices referenciam pontos de junção contidos nestas classes. 23 This watermark does not appear in the registered version - http://www.clicktoconvert.com 22 primeiro momento. Para compreender melhor esta noção é interessante primeiro falar a respeito da programação como é conhecida atualmente. Para se construir um aplicativo é possível utilizar a programação estruturada, onde são especificados alguns blocos de código que são conectados para construir sistemas mais complexos. É notório que, em algum momento, haverá um correspondente em código objeto para cada um dos blocos de código fonte implementados. Este é um tipo de mapeamento onde um segmento de código fonte corresponde diretamente a um segmento de código objeto. É possível também utilizar a programação OO para desenvolver este mesmo aplicativo imaginário. Neste tipo de abordagem é especificado um conjunto de classes que, encapsulando algum comportamento, colaborarão entre si de modo a atingir um objetivo comum. Estas classes serão instanciadas em algum momento em vários ou talvez em dezenas de objetos. A classe, em sua forma estática, terá correlação direta com suas instancias, os objetos. A representação conceitual do relacionamento classeobjeto é mostrada na fig. 2.8 logo abaixo. AMBIENTE DE EXECUÇÃO CLASSES Ponto Linha P1 P4 L1 P2 L2 L3 L4 P3 INSTÂNCIAS DE CLASSE Figura 2.8 – Relacionamento Classe-Objeto É possível afirmar que o tipo de correlação entre código fonte e código objeto nas abordagens procedural e OO é clara e é estática ao longo do tempo de 22 This watermark does not appear in the registered version - http://www.clicktoconvert.com 21 Um aspecto pode afetar diversos componentes do sistema e o conjunto de componentes afetados é determinado nos termos dos pontos de junção declarados nos advices. Compreender a forma pela qual o aspecto se relaciona com a classe é relevante diante dos conceitos apresentados. Na próxima seção será apresentado o relacionamento entre o aspecto e o conjunto de classes por ele afetadas. 2.5. O Relacionamento Aspecto – Classe Para que se possa contextualizar é necessário falar algo a respeito de classe e objeto apresentando idéias largamente aceitas atualmente. Uma classe é um modelo abstrato, possui atributos e métodos e implementa algum comportamento. Uma classe possui mecanismos que escondem/protegem sua estrutura interna. Ela pode ser especializada através do mecanismo de herança e sua subclasse apresentará, além do comportamento de sua superclasse, algum comportamento adicional (novos atributos e métodos). Uma classe pode ser instanciada na forma de objetos e estes objetos serão instâncias de uma mesma classe. Mas como ter certeza a respeito de quais objetos pertencem a uma mesma classe sendo que cada objeto é uma entidade que possui um estado próprio? Cada objeto possui um conjunto de valores próprios para seus atributos sim, e isto determina o estado do objeto em um determinado momento. Mas cada instância de classe possui também o conjunto de métodos declarados na sua classe correspondente. Esta característica define o conjunto de mensagens as quais um objeto tem condições de responder. Logo, todos os objetos capazes de enviar e responder ao mesmo conjunto de mensagens são considerados como pertencentes a uma mesma classe. O relacionamento classe-objeto é claro e apoiado pela vasta literatura disponível nos dias de hoje. Mas o relacionamento aspecto-classe difere deste. Neste tipo de relacionamento um segmento de código fonte não mapeia diretamente um segmento de código compilado. Em contrário, mapeia todas as instâncias de classe onde um determinado aspecto é aplicado. Mudar apenas uma linha de código poderá refletir as mudanças para toda a aplicação (ASPECT-ORIENTED PROGRAMMING (AOP), 2000). Esta afirmativa pode não parecer muito clara em um 21 This watermark does not appear in the registered version - http://www.clicktoconvert.com 20 Os advices são os componentes do modelo orientado a aspectos que são encapsulados pelos aspectos. Pode ser afirmado que o advice define sob quais critérios um aspecto afetará as classes do sistema. Os aspectos serão discutidos em maiores detalhes a seguir. 2.4.4. O Aspecto Conforme mencionado anteriormente o aspecto é uma unidade funcional que modulariza as responsabilidades comuns dos componentes do sistema. Os aspectos encapsulam advices. Os advices determinam sob quais critérios o aspecto afetará um determinado conjunto de componentes. Estes critérios são definidos pelos pontos de corte e pelos pontos de junção. A fig. 2.7 mostra que os métodos set() e get() das classes Ponto e Linha foram determinados como pontos de junção dos advices declarados no aspecto afetaPontoeLinha.Logo a execução destes métodos é o critério que determina quando e se o aspecto virá a afetar estas classes. Se estes métodos não forem invocados diz-se que os pontos de junção que eles representam não foram encontrados. Logo o advice que os encapsula não será executado e por consequência o aspecto onde este advice está contido também não será executado. O modelo orientado a aspectos está para a modularização das responsabilidades comuns assim como a OO está para o encapsulamento e a herança porque oferece mecanismos que permitem capturar estas responsabilidades (KICKZALES et al, 2001). Pode ser afirmado que o aspecto é uma unidade modular diferenciada dos demais componentes do sistema. Um aspecto tem a capacidade de encapsular advices, isto é uma verdade. Mas um aspecto pode simplesmente encapsular declarações ordinárias do modelo orientado objetos e nada mais, não declarando advice algum e possuindo o comportamento de uma classe ordinária. Sob este enfoque, um aspecto pode declarar variáveis e métodos, mas nenhum advice. Há de se considerar que talvez não faça sentido algum implementar aspectos que não encapsulem advices, mas isto serve ao menos para reforçar o caráter da POA em estender o modelo OO e não substituí-lo. 20 This watermark does not appear in the registered version - http://www.clicktoconvert.com 19 advice é executado Ponto de corte é executado Ponto de junção é encontrado ADVICE PONTO DE CORTE PONTO DE JUNÇÃO Figura 2.6 – Visão Conceitual do Advice Resta considerar um detalhe adicional. Uma noção temporal pode ser agregada ao advice (LESIECKI, 2002). Esta noção temporal determina que o comportamento adicional acrescentado pelo advice poderá ocorrer antes, depois ou mesmo concorrentemente aos pontos de corte quando os pontos de junção são encontrados. De forma objetiva, a característica temporal deve implicar que a execução do corpo do advice poderá ocorrer ‘antes de’, ‘depois de’ou ‘paralelamente a’ em relação ao corpo do ponto de junção. As noções ‘antes de’ e ‘depois de’ serão apresentados agora. A terceira noção será vista mais adiante com a aplicação direta da sintaxe AspectJ. Pode ser vista também no cap. 5. A fig. 2.7 apresenta esta noção temporal com base na anatomia do advice vista anteriormente na fig. 2.5. Aspecto afetaPontoeLinha; { Antes de : Ponto.setX(), Ponto.setY(), ... { O CORPO DO ADVICE É EXECUTADO ANTES DO CORPO DO PONTO DE JUNÇÃO } Depois de : Linha.getP1(), Linha.getP2(), .... { O CORPO DO ADVICE É EXECUTADO DEPOIS DO CORPO DO PONTO DE JUNÇÃO } } Figura 2.7 – Noção Temporal do Advice 19 This watermark does not appear in the registered version - http://www.clicktoconvert.com 18 componentes afetados pelo aspecto. A próxima seção explora com maiores detalhes este importante elemento da POA. 2.4.3. Advices O advice é um elemento do modelo orientado a aspectos que pode agrupar um ou mais pontos de corte. O conjunto de pontos de corte relacionados em um advice é que define em quais termos este advice será executado e quais classes ele irá afetar (KICKZALES et al, 2001). Ocorrendo a execução do advice algum comportamento adicional pode ser inserido podendo afetar diversas classes da aplicação. O conjunto exato destas classes é definido no advice nos termos dos pontos de corte nele contidos. A anatomia do advice é dada na fig. 2.5. 1-<antes, depois> : { 2-<pj1, pj2, .... pjn> 3-<Algum comportamento adicional aqui> } 1) advice tipo 2) ponto de corte 3)corpo Figura 2.5 – Anatomia do Advice Em uma visão conceitual, o advice pode ser considerado como o elemento mais externo aos pontos de corte e pontos de junção respectivamente. Sob este enfoque, advices podem ser definidos como segmentos de código que encapsulam pontos de corte que por sua vez encapsulam pontos de junção. A fig. 2.6 logo abaixo a representação desta visão conceitual. 18 This watermark does not appear in the registered version - http://www.clicktoconvert.com 17 diz-se que o ponto de junção foi encontrado. Quando um ponto de junção é encontrado o ponto de corte onde ele está contido é finalmente executado. Os pontos de junção definem os termos dos pontos de corte. 2.4.2. Pontos de Corte Os pontos de corte são mencionados na literatura sob o termo pointcut. Um ponto de corte pode ser definido como uma construção que descreve o agrupamento, sob um determinado critério, de um conjunto de pontos de junção. Os pontos de corte são executados a partir do momento em que os pontos de junção que o compõem são encontrados. Determinam desta forma os termos pelos quais o aspecto é inserido na aplicação (KICKZALES et al, 2001). Como forma de ilustrar tome-se como exemplo as classes Ponto e Linha já vistas na fig. 2.1. O conjunto de métodos implementados nestas classes podem ser considerados como sendo pontos de junção, pois determinam alguma ação sendo executada em algum lugar da aplicação. Logo podem ser agrupados de modo a especificar pontos de corte. A fig. 2.4 apresenta a caracterização de ponto de corte. Pontos de junção Ponto.setX(int) Ponto.SetY(int) ponto de corte Linha.setP1(Ponto) Linha.getP2(Ponto) Figura 2.4 – Pontos de Corte O ponto de corte mostrado na figura acima será executado somente quando algum dos eventos relacionados como pontos de junção forem encontrados. Por isso diz-se que os pontos de junção definem os termos dos pontos de corte. Havendo tomado consciência do termo ponto de corte estamos então preparados para lançar olhares sobre outro elemento essencial na definição do modelo orientado a aspectos : o advice. Este elemento é definido dos termos dos pontos de corte e, de forma resumida, determina algum comportamento adicional a ser adicionado aos 17 This watermark does not appear in the registered version - http://www.clicktoconvert.com 16 Desta maneira, nada que impediria que um objeto passível de invocar uma mensagem do tipo m1 invocasse um método que emitisse uma mensagem do tipo m2 e vice-versa. Os aspectos podem então ser aplicados na modularização destas responsabilidades comuns, evitando a replicação de código e a interdependência entre módulos o que caracteriza o entrelaçamento de código. Podem ser aplicados como forma de manter estas classes limpas, ou seja, portadoras apenas da estrutura primária do sistema. Estariam então livres das responsabilidades secundárias e desta forma concebidas sob um alto grau de modularização. 2.4. Os Elementos do Modelo Orientado a Aspectos Esta seção trata o conjunto e elementos que define o modelo orientado a aspectos. Serão vistos nesta ordem a definição de ponto de junção, ponto de corte, advice, introdução e aspecto. 2.4.1. Pontos de Junção Os pontos de junção são mencionados na literatura sob o termo join points. Eles são um elemento essencial no modelo orientado a aspectos. Determinam pontos definidos à partir dos quais uma operação qualquer é executada no sistema. De forma objetiva, são caracterizados por eventos que ocorrem em tempo de execução (KICKZALES et al, 2001). Podem ser considerados como exemplos típicos de pontos de junção os seguintes eventos: · Chamada de um método ou construtor; · Execução do corpo de um método ou construtor; · Execução de blocos de controle de exceções; · Atribuição de valores a variáveis. O conjunto exato de pontos de junção disponíveis é diretamente dependente da linguagem utilizada. Quando um evento relativo a um ponto de junção é executado, 16 This watermark does not appear in the registered version - http://www.clicktoconvert.com 15 aplicativo e utilizar recursos gráficos mais aprimorados como uma janela sofisticada por exemplo. Figura 2.3 - Modularização do Código Entrelaçado Como primeira opção bastaria alterar os métodos que implementam a emissão da mensagem. Uma alternativa eficiente mas pouco desejável sob o aspecto da manutenção à medida que o sistema cresce em complexidade. Em sistemas complexos talvez seja necessário procurar e alterar dezenas de métodos em dezenas de classes. Uma segunda opção seria declarar uma nova classe intermediária que implementasse todos os tipos de mensagens e assim encapsulasse este novo look and feel do aplicativo. Desta forma, com base no tipo de mensagem recebida dos objetos do sistema, uma mensagem específica seria emitida. Esta abordagem seria mais razoável sob o ponto de vista da manutenção, visto que haveria então uma classe responsável pela emissão de mensagens. Em contrapartida surgem duas novas desvantagens que podem não compensar o uso de tal estratégia. A primeira desvantagem e talvez mais óbvia seria a queda de performance visto que cada objeto afetado, sempre que necessitasse emitir uma mensagem, provocaria uma chamada de método a outro objeto. A segunda desvantagem é que não haveria forma de restringir o acesso dos objetos aos membros desta classe intermediária. 15 This watermark does not appear in the registered version - http://www.clicktoconvert.com 14 classes que faz acesso concorrente a dados. Aplicadas a um contexto onde o quesito concorrência não exista estas operações podem gerar algum overhead. Figura 2.2 – Entrelaçamento de Código O termo tangled code, caracterizado logo acima na fig. 2.2, define o oposto do que é considerado como clean code ou código limpo (LOPES & KICKZALES, 2000). O código limpo pode ser conseguido a partir do momento em que as responsabilidades comuns são detectadas e agrupadas em algum tipo de módulo reusável, e que possa ser posteriormente agregado pelas classes do sistema conforme, fig. 2.3. Conforme argumentado os efeitos mais visíveis do entrelaçamento são percebidos na forma de dificuldades na manutenção e o comprometimento da modularidade (KICKZALES et al, 1997, BÖLLERT, 2000). A percepção do termo entrelaçamento pode ser apurada à medida que analisamos situações recorrentes dentro da programação OO. Uma destas situações pode ser observada pela análise da fig. 2.1 - Classes Ponto e Linha. Cada método destas duas classes implementa seu próprio código de emissão de mensagens. Considere-se a hipótese de que um programador desejasse alterar algo a respeito destas mensagens. Quem sabe, ao invés de usar uma simples saída do tipo texto (System.out.println()), este programador desejasse alterar o look and feel do 14 This watermark does not appear in the registered version - http://www.clicktoconvert.com 13 Um aspecto pode ser considerado como sendo um segmento de código que representa uma propriedade recorrente dentro da aplicação. Ë uma abordagem que visa a eliminação das desvantagens geradas a partir do entrelaçamento de código. Ela apresenta as características vantajosas da OO mas apresenta também um diferencial que supera uma grande desvantagem desta: as responsabilidades comuns podem ser escritas apenas uma única vez e ser utilizadas em qualquer ponto da aplicação. 2.3. As Responsabilidades Comuns e o Entrelaçamento A separação de responsabilidades é um instrumento importante na engenharia de software pois é um recurso que permite lidar com a complexidade dos sistemas (WALKER et al, 2000). Mas as responsabilidades comuns quando codificadas a partir das abordagens tradicionais de programação(procedural e OO), geram o entrelaçamento de código, referido da literatura como tangled code (LOPES & KICKZALES, 2000). Nas abordagens tradicionais um módulo é representado por um bloco de código executável. Considere-se então uma aplicação com inúmeros módulos onde estes compartilham inúmeras responsabilidades comuns. O resultado final será um amontoado de código duplicado o que gera complexidade no entendimento e manutenção. O entrelaçamento está intimamente ligado à responsabilidade comum, visto que é gerado por ela. O entrelaçamento é tipicamente caracterizado por: · Replicação de código – é replicado código com as cláusulas de tratamento de exceções. Um aspecto poderia contemplar a responsabilidade tratamento de exceções; · Aumento da dependência entre módulos - a tentativa de implementar as responsabilidades secundárias em classes intermediárias aumenta a interdependência entre os módulos o que dificulta sua inserção em outro contexto; · Comprometimento da performance - determinado código pode as vezes ser restrito a contextos particulares. Um bom exemplo é dado por um conjunto de 13 This watermark does not appear in the registered version - http://www.clicktoconvert.com 12 forma como controle de concorrência não é a responsabilidade primária de uma classe projetada para acesso a dados (ASPECT-ORIENTED PROGRAMMING (AOP), 2000). Mas como tratar as responsabilidades comuns do sistema? A POA introduz um módulo reusável denominado Aspecto que encapsula as responsabilidades comuns das classes da aplicação inibindo a replicação de código. Na próxima seção serão discutidas as questões relacionadas a este elemento básico da POA. 2.2. O Aspecto como Unidade Funcional da Aplicação As metodologias de análise e projeto de sistemas evoluíram ao longo do tempo e representam conhecimento sólido a respeito de como produzir software reutilizável. Entretanto elas não oferecem abordagens que permitam ao desenvolvedor tratar o compartilhamento das responsabilidades comuns entre os módulos das aplicações. Tal característica deve-se ao fato de que estas metodologias foram desenvolvidas sob a premissa básica de que a unidade funcional do software é o módulo (ASPECT-ORIENTED PROGRAMMING (AOP), 2000). A abordagem OO apresenta diversas características vantajosas como encapsulamento, hierarquia e alto grau de modularidade. Porém como já pôde ser observado na fig. 2.1, classes não são funcionais no que diz respeito às responsabilidades sistêmicas que extrapolam suas fronteiras: as responsabilidades comuns. A natureza do módulo está em definir e implementar a estrutura primária do sistema. As responsabilidades secundárias – que podem vir a assumir o caráter de responsabilidade comum - surgem como um efeito colateral indesejado e muitas vezes inevitável. Elas acabam então sendo agregadas à estrutura principal do sistema, aumentando o código em volume e complexidade. O aspecto pode ser descrito como uma unidade funcional que encapsula um comportamento comum a diversas classes do sistema (LESIECKI, 2002). Este comportamento comum é representado pelas responsabilidades comuns, logo o aspecto é uma unidade que encapsula as responsabilidades comuns das classes da aplicação. 12 This watermark does not appear in the registered version - http://www.clicktoconvert.com 11 responsabilidade comum a ambas que é a impressão de mensagens. Seria possível modularizar a emissão de mensagens em uma classe intermediária. Entretanto surgiriam dois efeitos imediatos : · Dependência das classes Ponto e Linha para com esta terceira classe o que gera diminuição do grau de reusabilidade; · Maior overhead na chamada de métodos quando uma mensagem “W” ou “R” precisasse ser impressa. Outra situação típica do que seria uma responsabilidade comum poderia ser o controle de exceções. Tome-se uma aplicação composta por inúmeras classes. Para cada classe são declarados inúmeros métodos que realizam operações diversas(acesso a dados, comunicação remota, alocação de recursos entre outros). É pertinente presumir que deverá haver o controle dos erros que poderão vir a ocorrer durante a execução destas operações. Estes métodos irão declarar suas próprias cláusulas catch e tratarão seus erros de forma independente sempre que eles ocorrerem. Esta é a forma pela qual este problema pode ser resolvido no paradigma OO. Então todos os métodos que realizam operações sobre dados deverão ter a capacidade de tratar os erros decorrentes do acesso a dados. Também todos os métodos que realizam operações de comunicação remota deverão ter a capacidade de tratar os erros decorrentes de falha de comunicação e assim por diante. A primeira conclusão e talvez a mais óbvia é que responsabilidade comum significa a constante replicação de segmentos de código. É replicado código para cláusulas de tratamento de erros, para controle de acesso compartilhado a dados, para processos de logging e várias outras operações. Esta característica pode ser observada nas classes Ponto e Linha onde a responsabilidade comum de emissão de mensagens é caracterizada pela replicação do código relativo a esta operação. Cabe outra observação importante e não tão óbvia quanto a mencionada acima. A responsabilidade comum não significa essencialmente responsabilidade primária. Ao contrário, responsabilidades comuns têm como principal característica o fato de serem responsabilidades secundárias dentro das classes do sistema. Da mesma 11 This watermark does not appear in the registered version - http://www.clicktoconvert.com 10 1 Class Ponto 2 { 3 int _x = 0; 4 int _y = 0; 5 6 int getX () 7 { 8 System.out.println(“R”); 9 Return _x; 10 } 11 12 void setX (int x) 13 { 14 System.out.println(“W”); 15 _x = x; 16 } 17 18 void setY (int y) 19 { 20 System.out.println(“W”); 21 _y = y; 22 } 23 } 1 Class Linha 2 { 3 Ponto _P1; 4 Ponto _P2; 5 6 Void setP1 (Ponto) 7 { 8 System.out.println(“W”); 9 _P1 = Ponto; 10 } 11 12 void setP2 (Ponto) 13 { 14 System.out.println(“W”); 15 _P2 = Ponto; 16 } 17 18 Ponto getP2 () 19 { 20 System.out.println(“R”); 21 Return _P2; 22 } 23} Figura 2.1 - Classes Ponto e Linha Para que se possa compreender melhor o conceito vamos observar as classes Ponto e Linha descritas acima. Pode ser visto que ambas modularizam suas responsabilidades primárias que são : · A classe Ponto representa pontos no plano; · A classe Linha representa uma linha formada a partir da junção de dois pontos. Entretanto existe uma responsabilidade comun compartilhada entre estas duas classes que é a impressão de mensagens : · Os métodos set...() de ambas as classes, quando invocados, devem emitir uma mensagem ‘W’; · Os métodos get...() de ambas as classes, quando invocados, devem emitir uma mensagem ‘R’. Eis então que estas classes, além de implementarem suas responsabilidades primárias que é representar algo sobre pontos e linhas, implementam também uma 10 This watermark does not appear in the registered version - http://www.clicktoconvert.com 9 Elas são a essência da POA e são referidas na literatura como crosscutting concerns ou crosscuts (VOELTER, 2000). A aplicação do termo crosscut define a natureza da responsabilidade comum como algo ‘passante’, algo que traspassa a estrutura primária das classes do sistema. Ela não pode ser codificada como uma responsabilidade particular bem definida. Ao contrário, é uma responsabilidade compartilhada por múltiplas classes dentro da aplicação. “Ë uma característica que atravessa a aplicação afetando o comportamento de inúmeras classes não podendo ser codificada como uma responsabilidade bem definida de uma única classe” (ASPECT- ORIENTED PROGRAMMING (AOP), 2000). Um dos princípios básicos da OO é a definição das responsabilidades para as classes do sistema. Cada coisa é feita em um único lugar. Por este motivo a responsabilidade comum, na sua definição, é um elemento que viola este princípio básico (VOELTER, 2000). Ao contrário de espalhar o código relativo a uma responsabilidade do sistema ao longo de diversos componentes a linguagem de programação deve oferecer a possibilidade de expressar esta responsabilidade em um único e coerente pedaço de código – uma classe, um módulo, etc (WALKER et al, 2000, ASPECTJ DOCUMENTATION AND RESOURCES, 2002). À primeira vista a consolidação do conceito responsabilidade comum aplicado sobre um modelo que prega a divisão de responsabilidades pode parecer difícil de ser concebido. Pode parecer até mesmo um paradoxo. Mas uma visão mais apurada pode mostrar que o conceito responsabilidade comum é de fato infligido sobre o modelo OO e agride o princípio básico da modularidade (LOPES & KICKZALES, 2000). É interessante observar a fig. 2.1 - Classes Ponto e Linha. Estas classes possuem uma implementação muito simples onde nas operações set...() é impressa uma mensagem “W” e nas operações get...() é impressa uma mensagem “R”. O código referente à impressão destas mensagens pode ser visto nas linhas 8, 14 e 20 destas classes. Estes segmentos de código representam as responsabilidades comuns implementadas nestas classes. 9 This watermark does not appear in the registered version - http://www.clicktoconvert.com 8 Capítulo II O Modelo Orientado a Aspectos A abordagem OO tem se destacado nos últimos anos dando a impressão de haver substituído de forma completa a abordagem procedural. Sem sombra de dúvida, a abordagem OO tem muitas vantagens sobre sua precedente. A definição de classes abstratas induz a um alto grau de modularização. Os objetos possuem responsabilidades definidas e colaboram entre si de modo atingir um objetivo comum. Há de ser mencionado também o forte grau de reusabilidade alcançado. De fato o que se espera de um aplicativo concebido sob a abordagem OO é que o resultado final seja um projeto modularizado e limpo que nos leve a produzir código também modularizado e limpo. A modularidade, reusabilidade e definição de responsabilidades que são oferecidos pelo modelo OO são recursos que certamente contribuem em tempos onde o tamanho e a complexidade dos artefatos de software cresce a olhos vistos. Mas existem responsabilidades que, pela sua natureza, não podem ser definidas e codificadas como responsabilidade de uma única classe. Elas ultrapassam a fronteira do objeto e necessitam ser tratadas pelo conjunto de classes do sistema. Logo degradam a noção de modularização defendida pelo modelo OO. Estas responsabilidades são denominadas como responsabilidades comuns. A POA surge então como uma nova forma de construir código onde as responsabilidades comuns são capturadas e modularizadas, podendo ser reutilizadas nos diversos segmentos de código onde são requeridas. 2.1. Responsabilidades Comuns - Fundamento do Alto Nível de Abstração da POA As responsabilidades comuns são responsabilidades que não podem ser concebidas como pertencentes a uma única classe. Elas afetam diversos componentes da aplicação e necessitam então ser incluídas em todo o conjunto de componentes afetados. 8 This watermark does not appear in the registered version - http://www.clicktoconvert.com 7 Na segunda versão é aplicada a abordagem proposta no cap. 4, produzindo assim uma versão otimizada e mais reutilizável. São apresentadas as deficiências detectadas na primeira versão e os benefícios posteriormente obtidos com a versão POA do aplicativo. Capítulo 6 São discutidos os resultados obtidos em relação aos objetivos apresentados na seção 1.2 e também são feitas sugestões para trabalhos futuros. 7 This watermark does not appear in the registered version - http://www.clicktoconvert.com 6 1.1. Objetivos Esta dissertação tem como objetivo um estudo sobre a aplicação da POA no desenvolvimento de projetos reutilizáveis de software sob duas diretrizes básicas que são: 1) modularização das responsabilidades comuns presentes nas classes do sistema; 2) a modularização das RCE para a validação do modelo orientado a aspectos na produção de softwares reutilizáveis. 1.2. Organização Capitulo 2 É apresentada a fundamentação a respeito dos conceitos do modelo orientado a aspectos. São definidos os conceitos fundamentais do paradigma como aspecto, advice, ponto de corte, ponto de junção e introduções. Capítulo 3 É apresentada a linguagem de programação AspectJ, que é uma implementação para os conceitos da orientação a aspectos. Capítulo 4 É apresentada uma nova visão do modelo orientado a aspectos que é a aplicação da POA no desenvolvimento de projetos reutilizáveis de software. Esta nova visão da aplicação dos aspectos é apresentada na forma uma abordagem definida como modularização das RCE. É também proposta uma metodologia para o processo de modularização das RCE e a restruturação do sistema para uma versão mais otimizada do ponto de vista da reutilização. Capítulo 5 É apresentado o desenvolvimento do aplicativo Figuras Flutuantes. Este aplicativo é mostrado em duas versões: a primeira sob uma abordagem totalmente OO e a segunda versão agora migrando para o paradigma da orientação a aspectos. 6 This watermark does not appear in the registered version - http://www.clicktoconvert.com 5 Como meio de alcançar o objetivo de desenvolvimento de projetos de software reutilizáveis é proposta uma metodologia para a identificação e modularização das RCE. As RCE estão relacionadas à efetividade do mecanismo de herança nos termos descritos acima. Isto porque elas representam o conjunto de operações que, estando declarados nas classes do sistema como fator de reusabilidade, tornam-se subutilizadas ou mesmo obsoletas quando a classe se encontra inserida em um contexto particular. A modularização das RCE nos permite que as classes do sistema implementem em sua estrutura apenas as operações comuns aos possíveis contextos onde o sistema poderá vir a executar. As operações específicas ao contexto serão agregadas apenas quando necessário. O resultado final esperado para o aplicativo é a sua adaptabilidade a diversos contextos porém implementando apenas operações essenciais a todos eles. Como forma de viabilizar a proposta foi desenvolvido um aplicativo gráfico simples onde não são aplicados quaisquer recursos sofisticados oferecidos atualmente pelo modelo OO. Desta foram abolidos propositadamente da modelagem apresentada neste trabalho a inclusão de padrões de projeto que pudessem eventualmente otimizar a arquitetura. Esta decisão foi tomada em função da proposta aqui apresentada que concentra-se pura e simplesmente na efetividade do mecanismo de herança do modelo OO, conforme exposto nos parágrafos acima. O objeto é avaliar os benefícios da POA especificamente no que tange à possibilidade do tratamento desta efetividade. A aplicação de padrões de projeto ou outros recursos apenas alargariam o escopo deste trabalho. Finalmente acredita-se que este trabalho venha ser algo que possa somar aos inúmeros esforços empreendidos na área de otimização de software. Que possa contribuir de alguma forma na avaliação da abordagem POA que apesar de recente tem sido objeto de diversos estudos e que possa ser de algum valor na avaliação das suas contribuições reais ao modelo OO. 5 This watermark does not appear in the registered version - http://www.clicktoconvert.com 4 Este mecanismo representa algo de muito vantajoso visto que não precisamos gastar tempo refazendo operações que já foram codificadas uma vez. É possível reutilizar ou alterar métodos das superclasses existentes bem como incluir novos membros nas subclasses. São obtidas então modularidade, reusabilidade e toda a gama de vantagens oferecidas pela abordagem orientada a objetos. Mas o modelo OO não prevê mecanismos que permitam a distinção entre as operações que realmente vão ser utilizadas por uma instância de classe em um contexto particular daquilo que pode ser considerado como uma ‘herança inútil’. O termo herança inútil pode ser entendido como uma referência a um atributo ou um método declarado na classe e que foi herdado pela sua instância, mas não se aplica ao contexto onde esta instância se encontra inserida no momento. É um mecanismo efetivo porque é aplicado a todos os atributos e métodos declarados por uma classe. Como resultado implica que todas as suas instâncias e também todas as instâncias de suas subclasses herdarão todo um conjunto de operações indiscriminadamente. De um modo geral se considerarmos uma classe que implementa um grande número de operações onde algumas são aplicadas somente a contextos específicos, pode-se chegar a situações onde: · Operações não necessárias ao contexto atual estão permanentemente presentes nas instâncias desta classe gerando algum aumento do código executável; · Operações são implementadas de forma genérica para serem aplicadas a todos os contextos gerando algum overhead. Seria interessante do ponto de vista da reutilização se as instâncias das classes herdassem apenas o conjunto de operações necessárias e que realmente vão ser utilizadas durante seu período de execução. Desta forma, independentemente do perfil genérico da classe, a instância seria sempre uma entidade especializada para o contexto onde se encontra inserida. 4 This watermark does not appear in the registered version - http://www.clicktoconvert.com 3 · Compiladores inteligentes – as compilações JIT, dinâmica e adaptativa promovem alterações no código executável visando otimização do uso dos recursos de hardware e aumento do desempenho ( XUE et al, 2001, RICHTER, 2002, HARDWIK, 1997, HOMEPAGE BY IBM LABS - JIT/400, 1999); · Otimização de bytecodes – é possível pensar em melhoramentos da estrutura do arranjo de bytecodes de Java visando aumento do desempenho em situações específicas (HARDWIK, 1997, JENSEN, 2000, JENSEN, 2001, APPLE COMPUTER INC. - AUTOMATED CODE OPTIMIZATION, 2001, S5 SYSTEMS INC - BYTE CODE OPTIMIZATION, 2002, SHUDO, 2002). As técnicas são variadas, mas a motivação central para o estudo e desenvolvimento de técnicas de otimização giram em torno de duas diretrizes básicas que são : a) como diminuir o tamanho do código executável visando consumir menos recursos de processamento e memória; b) como tornar sua execução mais rápida. Circunscrito neste enfoque da otimização surge a POA (Programação Orientada a Aspectos) idealizada por pesquisadores da Xerox PARC (KICKZALES et al, 1997). É importante observar que o modelo orientado a aspectos não vêm em substituição, mas em adição ao modelo OO sob a promessa da modularização das responsabilidades comuns como forma de obter algum grau de otimização para as classes do sistema. O modelo de aspectos permite de fato a modularização das responsabilidades comuns de uma forma natural, eliminando a replicação de código que é seu maior objetivo. Entretanto a contribuição deste trabalho está em lançar uma visão diferenciada sobre a POA, objetivando a aplicação do modelo orientado a aspectos no desenvolvimento de projetos de software reutilizáveis. A origem da proposta aqui apresentada concentra-se em uma característica intrínseca do modelo OO e que pode de alguma forma ser tratada pela orientação a aspectos: o mecanismo de herança. 3 This watermark does not appear in the registered version - http://www.clicktoconvert.com 2 melhor desempenho. Para uma aplicação destinada a resolver um problema em particular é possível: · Aplicar uma linguagem orientada a domínio ao invés de uma linguagem de propósito geral; · Aplicar construções da linguagem que sejam específicas ao domínio do problema ao invés de aplicar estruturas genéricas de forma indiscriminada. De modo geral, este tipo de aplicação pode agregar apenas os recursos estritamente necessários ao domínio do problema em questão. Como consequência estes aplicativos consomem menos recursos de memória e processador, são mais simples de serem desenvolvidos e mantidos e, geralmente, têm melhor desempenho. Em contraponto à vantagem oferecida pela sua especificidade, este tipo de componente de software pode apresentar uma característica desvantajosa: o seu grau de reusabilidade pode ser muito reduzida. Isto talvez torne difícil integrá-lo a outros componentes tornando difícil adaptá-lo a diferentes contextos a menos que sejam realizadas customizações manuais. São observadas situações antagônicas onde é preciso escolher uma das seguintes opções: a) um componente de bom desempenho, mas com menor reusabilidade; b) um componente com maior grau de reusabilidade, mas que é mais oneroso em termos do consumo de recursos. O ideal perseguido, e talvez utópico, seria classes genéricas e reusáveis que sejam capazes de alcançar o nível de otimização de classes especializadas sempre que requisitado por um contexto específico. Surgem então esforços no desenvolvimento de técnicas que possam amenizar a queda de desempenho, com o intuito de produzir algum grau de otimização. Dentre as mais conhecidas encontram-se: 2 This watermark does not appear in the registered version - http://www.clicktoconvert.com Capítulo I Introdução A explosiva evolução do hardware torna-se evidente a cada vez que surgem processadores mais poderosos, memórias de acesso mais rápido e mídias mais potentes. A maior disponibilidade de recursos tem determinado uma característica dominante a respeito dos componentes de software: sua genericidade. A abordagem OO tem se destacado nos últimos anos dando a impressão de haver substituído de forma completa a abordagem procedural. Sem sombra de dúvida a abordagem OO tem muitas vantagens em relação à sua precedente. A definição de classes abstratas induz a um alto grau de modularização. Os objetos possuem responsabilidades definidas e colaboram entre si de modo atingir um objetivo comum. Há de ser mencionado também o alto grau de reusabilidade que pode ser alcançado. De fato o que se espera de um aplicativo concebido sob a abordagem OO é que o resultado final seja um projeto modularizado e limpo e que nos leve a produzir código também modularizado e limpo. A modularidade, reusabilidade e definição de responsabilidades que são oferecidos pelo modelo OO são recursos que certamente contribuem em tempos onde o tamanho e a complexidade dos artefatos de software cresce a olhos vistos. Um artefato genérico é reusável, capaz de interagir com outros componentes, executar em diversas plataformas e adaptar-se a diversos contextos diferentes. As soluções genéricas pelo fato de serem projetadas para um domínio de aplicações podem arrastar consigo vastas bibliotecas de recursos, interpretadores e outros mecanismos e construções de uso geral implementados na linguagem. O resultado final é o aumento natural do custo de memória e processamento. As soluções projetadas para uma aplicação específica consomem menos recursos, são mais simples de serem desenvolvidas e mantidas e de modo geral têm This watermark does not appear in the registered version - http://www.clicktoconvert.com x Abstract This dissertion develops a study on the use of AOP(Aspect Oriented Language) in the production of reusable software projects. The main project strategy used was the modularization of CSR(Context Specific Responsabilities) in shape of aspects, so that the classes implement only de operations related to their primary structure. A simple graphic software called Floating Pictures was developed. In this software the CSR were modularizated. This software is constituted of classes that implement only a small set of operations that are common to both of the distinct contexts where it was executed. The operations related to the particuarities of these two contexts started to be agregated by the system classes only when necessary. The results showed that the some group of classes could be used for different necessities, achieving with success the objective of using AOP in the development of reusable software projects. x This watermark does not appear in the registered version - http://www.clicktoconvert.com ix Resumo Esta dissertação desenvolve um estudo sobre a utilização da POA(Programação Orientada a Aspectos) na produção de projetos de software reutilizáveis. A principal estratégia de projeto utilizada foi a modularização das RCE (Responsabilidades do Contexto Específico) na forma de aspectos, para que as classes implementem apenas o conjunto de operações relativas à sua estrutura primária. Desenvolveu-se um software gráfico simples chamado Figuras Flutuantes no qual as RCE foram modularizadas. Este software constitui-se de classes que implementam apenas um pequeno conjunto de operações comuns aos dois contextos distintos onde foi executado. As operações relacionadas às particularidades destes dois contextos passaram a ser agregadas pelas classes do sistema apenas quando necessárias. Os resultados mostraram que o mesmo conjunto de classes pôde ser aplicado a necessiades diferenciadas, atingido com sucesso o objetivo de aplicar a POA no desenvolvimento de projetos de software reutilizáveis. Palavras-chave: orientação a aspectos, projeto de software, reutilização, programação. ix This watermark does not appear in the registered version - http://www.clicktoconvert.com viii Lista de Acrônimos JIT Just In Time JVM Java Virtual Machine OO Orientação a Objetos POA Programação Orientada a Aspectos RCE Responsabilidades do Contexto Específico TAO Taxa de Aplicação das Operações UML Unified Modeling Language viii This watermark does not appear in the registered version - http://www.clicktoconvert.com vii Figura 4.5 – Classe acessaDados Restruturada...............................................................53 Figura 4.6 – Aspecto acessoRemoto................................................................................54 Figura 4.7 – Tecendo o Aspecto acessoRemoto..............................................................54 Figura 4.8 – Classe acessaDados Agregando RCE.........................................................55 Figura 4.9 – Instancias da Classe acessaDados e as RCE Agregadas............................56 Figura 4.10 – Nova Configuração de Contextos para a Classe acessaDados.................58 Figura 5.1 – Esquema de Conexões do Aplicativo..........................................................62 Figura 5.2 – Colisão entre Figuras...................................................................................62 Figura 5.3 – Diagrama de Classes do Sistema.................................................................64 Figura 5.4 – Replicação de Código para Tratamento de Exceções.................................67 Figura 5.5 – Referências entre as Classes do Sistema.....................................................68 Figura 5.6 –Classes do Sistema sem a Modularização das RCE.....................................69 Figura 5.7 – Tratamento de Exceções das Classes do Sistema.......................................72 Figura 5.8 – Aspecto trataExcecao.................................................................................75 Figura 5.9 – Tabulação RCE das Classes Circulo, Triangulo e Retangulo.....................77 Figura 5.10 – Tabulação RCE da Classe Display............................................................78 Figura 5.11 – Tabulação RCE da Classe Registrador.....................................................79 Figura 5.12 – O Aspecto Navegacao...............................................................................81 Figura 5.13 – O Aspecto pintaLinhas..............................................................................83 Figura 5.14 – O Aspecto trataColisao.............................................................................84 Figura 5.15 – O Aspecto reduzTempoDeVida.................................................................86 Figura 5.16 – O Aspecto protecaoDoRegistro................................................................88 Figura 5.17 – Aplicativo Figuras Flutuantes com a Modularização das RCE................92 vii This watermark does not appear in the registered version - http://www.clicktoconvert.com vi Lista de Figuras Figura 2.1 – Classes Ponto e Linha................................................................................10 Figura 2.2 – Entrelaçamento de Código..........................................................................14 Figura 2.3 – Modularização do Código Entrelaçado................................................... ...15 Figura 2.4 – Pontos de Corte...........................................................................................17 Figura 2.5 – Anatomia do Advice....................................................................................18 Figura 2.6 – Visão Conceitual do Advice........................................................................19 Figura 2.7 – Noção Temporal do Advice.........................................................................19 Figura 2.8 – Relacionamento Classe-Objeto...................................................................22 Figura 2.9 – Aspecto Referenciando Duas Classes.........................................................23 Figura 2.10 – Relação Aspecto-Classe............................................................................24 Figura 3.1 – Aspectj como Solução de Propósito Geral..................................................28 Figura 3.2 – Ponto de Corte AspectJ...............................................................................29 Figura 3.3 – Ponto de Corte Nomeado Declarado como Membro de Classe..................30 Figura 3.4 – Pontos de Corte Abstratos..........................................................................31 Figura 3.5 – Ponto de Corte sem Retorno de Valor........................................................32 Figura 3.6 – Ponto de Corte com Retorno do Objeto Chamado.....................................32 Figura 3.7 – Ponto de Corte com Retorno do Objeto Passado como Parâmetro............33 Figura 3.8 – Ponto de Corte com Retorno de Dois Objetos............................................33 Figura 3.9 – Ponto de Corte com Retorno de Um Objeto e Um Valor Inteiro...............33 Figura 3.10 – Regra Geral de Parametrização.................................................................34 Figura 3.11 – Introduzindo Novos Membros na Classe Ponto....................................... 35 Figura 3.12 – Advice Around()........................................................................................36 Figura 3.13 – Anatomia do Aspecto................................................................................38 Figura 3.14 – Tecimento Estático Aplicando Inline........................................................39 Figura 3.15 – Tecimento Estático por Composição Explícita.........................................40 Figura 3.16 – Classe e Métodos Tecidos.........................................................................41 Figura 3.17 – Diagrama de Estados da Classe Tecida C`...............................................42 Figura 4.1 – Contextos Aplicados a Classe acessaDados...............................................46 Figura 4.2 – Responsabilidades Comuns x RCE.............................................................48 Figura 4.3 – Tabulação RCE da Classe acessaDados.....................................................52 Figura 4.4 – Identificação das RCE da Classe acessaDados..........................................53 vi This watermark does not appear in the registered version - http://www.clicktoconvert.com v Capítulo VI Conclusão........................................................................................................................95 6.1. Sugestão para Trabalhos Futuros............................................................... 95 Referências Bibliográficas...............................................................................................96 ANEXO 1......................................................................................................................100 ANEXO 2......................................................................................................................101 ANEXO 3......................................................................................................................106 v This watermark does not appear in the registered version - http://www.clicktoconvert.com iv Capítulo IV Desenvolvimento de Projetos de Software Reutilizáveis – Uma Visão Diferenciada do Modelo Orientado a Aspectos.........................................................................................43 4.1. O Conceito de RCE...................................................................................... 43 4.2. Responsabilidade Comum x RCE................................................................ 48 4.3. Uma Convenção para Identificação das RCE.............................................. 50 Capítulo V Um Projeto de Software Reutilizável Utilizando POA – Uma Abordagem Otimizada da Orientação a Aspectos.................................................................................................... 59 5.1. Características Gerais do Aplicativo............................................................ 59 5.1.1. O Contexto C1.............................................................................. 60 5.1.2. O Contexto C2.............................................................................. 63 5.2. A Versão OO do Aplicativo......................................................................... 63 5.2.1. As Responsabilidades para as Classes do Sistema........................ 65 5.2.2. As Deficiências Detectadas........................................................... 66 5.2.2.1. Entrelaçamento de Código............................................. 67 5.2.2.2. Herança de Operações Obsoletas ao Contexto C2......... 69 5.3. A Versão POA do Aplicativo...................................................................... 71 5.3.1. A Modularização das Responsabilidades Comuns....................... 71 5.3.2. A Modularização das RCE............................................................ 75 5.3.2.1. O Aspecto Navegacao.................................................... 81 5.3.2.2. O Aspecto pintaLinhas................................................... 83 5.3.2.3. O Aspecto trataColisao.................................................. 84 5.3.2.4. O Aspecto reduzTempoDeVida...................................... 85 5.3.2.5. O Aspecto protecaoDoRegistro..................................... 87 5.3.3. Os Benefícios Obtidos.................................................................. 89 5.3.3.1. Benefícios da Modularização das Responsabilidades Comuns........................................................................................89 5.3.3.2. Benefícios da Modularização das RCE...........................90 5.4. Crítica ao Modelo Orientado a Aspectos..................................................... 93 iv This watermark does not appear in the registered version - http://www.clicktoconvert.com iii Sumário Capítulo I Introdução......................................................................................................................... 1 1.1 Objetivos......................................................................................................... 6 1.2 Organização.................................................................................................... 6 Capítulo II O Modelo Orientado a Aspectos...................................................................................... 8 2.1. Responsabilidades Comuns – Fundamento do Alto Nível de Abstração da POA...................................................................................................................... 8 2.2. O Aspecto como Unidade Funcional da Aplicação..................................... 12 2.3. As Responsabilidades Comuns e o Entrelaçamento.................................... 13 2.4. Os Elementos do Modelo Orientado a Aspectos......................................... 16 2.4.1. Pontos de Junção.......................................................................... 16 2.4.2. Pontos de Corte............................................................................. 17 2.4.3. Advices.......................................................................................... 18 2.4.4. O Aspecto...................................................................................... 20 2.5. O Relacionamento Aspecto-Classe.............................................................. 21 Capítulo III Projeto Orientado a Aspectos com Aspectj.................................................................... 26 3.1. O Modelo de Pontos de Junção................................................................... 29 3.2. O Modelo de Pontos de Corte..................................................................... 29 3.2.1. A Nomeação dos Pontos de Corte................................................ 30 3.2.2. Parametrização dos Pontos de Corte............................................ 32 3.3. Introduções.................................................................................................. 34 3.4. Os Advices.................................................................................................... 36 3.4.1. A Ordem de Precedência dos Advices........................................... 37 3.5. Aspectos....................................................................................................... 37 3.6. Tecedor de Aspectos e Classes – Aspect Weaver........................................ 38 iii This watermark does not appear in the registered version - http://www.clicktoconvert.com ii Um Estudo sobre a Utilização de Aspectos no Desenvolvimento de Projetos Reutilizáveis de Software Carlos Alberto Barth Esta Dissertação foi julgada adequada para a obtenção do título de Mestre em Ciência da Computação Área de Concentração Sistemas de Computação e aprovada em sua forma final pelo Programa de Pós-Graduação em Ciência da Computação. ________________________________ Prof. Fernando A. Ostuni Gauthier, Dr. Coordenador Banca Examinadora ___________________________________ Prof. Rosvelter João Coelho da Costa, Dr. Orientador ___________________________________ Prof. Mario A. R. Dantas, Dr. ___________________________________ Prof. Roberto Willrich, Dr. ii This watermark does not appear in the registered version - http://www.clicktoconvert.com UNIVERSIDADE FEDERAL DE SANTA CATARINA PROGRAMA DE PÓS-GRADUAÇÃO EM CIÊNCIA DA COMPUTAÇÃO Carlos Alberto Barth Um Estudo sobre a Utilização de Aspectos no Desenvolvimento de Projetos Reutilizáveis de Sofware Dissertação submetida à Universidade Federal de Santa Catarina como parte dos requisitos para a obtenção do grau de Mestre em Ciência da Computação. Prof. Rosvelter João Coelho da Costa Orientador Florianópolis, Outubro de 2003