A necessidade urgente do uso da abstração, do reuso e baixo acoplamento fez da década de 80 um grande salto tanto para a POA (Programação Orientada a Aspectos) quanto para a POO (Programação Orientada a Objetos). Um dos problemas para se aplicar essas soluções no contexto de fábrica de software foi a necessidade de separar requisitos sistêmicos de requisitos funcionais.

WINCK e GOETTEN(2006) apude PIVETA(2001) revela que linguagem de aspectos deve suportar a implementação das propriedades desejadas de forma clara e concisa, fornecendo construções necessárias para que o programador crie estruturas que descrevam o comportamento dos apectos e definam em que situação eles ocorrem.

Ao desenvolver um sistema utilizando POA, o código referente ao domínio da aplicação não sofre nenhuma alteração, apenas é criada uma camada intermediária, isso é conhecido como Combinação Aspectual, o qual é um processo que antecede a compilação e capacita a aplicação a fazer a operação desejada em tempo de execução. Porém a combinação Aspectual dá-se das seguintes formas:

  • Dinâmica: necessita que os aspectos estejam presentes tanto em tempo de compilação quanto em tempo de execução.
  • Estática: não necessita que os aspectos estejam presentes nem em tempo de compilação quanto em tempo de execução, podendo trazer agilidade ao processo possibilitando um impacto positivo na performance do sistema.

O autor TEIXEIRA,I(2010) destaca que na Combinação Aspectual o compilador/combinador de aspectos não gera um código final e sim um novo código escrito na linguagem de componentes que será utilizada, por exemplo em Java. Isso significa dizer que POA é caracterizada como meta-programação (ao fim de sua execução é criado um código em uma nova linguagem), com isso torna-se impossível programar somente orientado a aspectos, fazendo-se necessário uma linguagem que represente no mundo computacional, os conceitos do mundo real, implementando as regras de negócio.

POA, UMA POSSÍVEL SOLUÇÃO

Adotar padrões de software para implementar os requisitos sistêmicos, como por exemplo o padrão Observer, que tem como principal função “escutar” quando uma determinada ação for executada, como por exemplo a alteração de estado de um objeto.

Já o padrão Decorator é utilizado quando se precisa atribuir uma funcionalidade a um objeto em tempo de execução, de modo que não deixe o código acoplado.

Entretanto o padrão Interceptor entra em ação quando há uma chamada a um determinado método.

Esses são exemplos de padrões que podem ser vistos como um começo para entender o conceito de POA, mas mesmo assim somente utilizando esses padrões em um projeto de software pode não ser a solução adequada, pois neste caso temos a junção do domínio da aplicação com interesses sistêmicos deixando o código emaranhado, popularmente conhecido como código macarrônico. Dessa forma a POO perde dois de seus principais objetivos, baixo acoplamento e coesão

Antes da POA

Figura 1: Antes da POA

Depois da POA

Figura 2: Depois da POA

Há três formas comuns para aplicar POA:

  • Em uma mesma classe;
  • Definido em arquivo separado;
  • Como membro de uma classe.

Os Join Points (ponto de junção) é o ponto onde aplica-se um interesse transversal por meio de aspecto, como por exemplo a chamada de métodos, construtores, tratamento de exceções e outros. Dessa forma podemos ter os pontos de atuação que tem como função capturar as chamadas aos pontos de função, podendo assim ter mais de um ponto de junção para um ponto de função.

Mais de um ponto de junção para um ponto de função

Figura 3: Mais de um ponto de junção para um ponto de função

Segundo WINCK e GOETTEN, um aspecto é o mecanismo disponibilizado pela Programação Orientada a Aspectos para agrupar fragmentos de código referentes aos componentes não-funcionais em uma unidade no sistema. Nesse caso, poderíamos dizer que aspecto-objeto é o principal de um programa orientado a aspectos, da mesma forma o objeto seria o principal em um programa orientado a objetos.

Aplicação de POA

Sempre que há a necessidade de separar os interesses sistêmicos dos interesses funcionais, isso torna a manutenção do sistema mais simples, pois a POA é dotada de mecanismos bastante eficazes que modularizam as políticas de sincronização, da mesma forma deixa a aplicação bem mais transparente, o que torna facultativo a refatoração do código. Onde encontramos mais uso da Orientação a Aspectos é na camada de persistência, que de forma transparente abstrai a implementação da persistência da camada de negócios da aplicação. Um exemplo clássico desse uso é o framwork Spring, que por meio da injeção de dependência consegue atuar na hora certa que for preciso fazer uma conexão com o banco de dados, executar uma ação e finalizar a conexão quando o resultado for retornado.

Para se entender a aplicação da POA em uma aplicação Java, é preciso saber diferenciar os pontos de junção dos pontos de atuação, um ponto de atuação tem como finalidade definir um ponto de junção, ou seja os pontos de atuação irão definir quais eventos serão considerados pontos de junção.

Listagem 1: Classe Java


	package br.com.nooclix.aspectos;
public class Pessoa {
	private String nome;
	private String sobrenome;
	public void salvar(String nome, String sobrenome){
		this.nome = nome;
		this.sobrenome = sobrenome;
	}
	//getts and setters
}

Para o método salvar( ) da classe Pessoa, pode-se definir um ponto de atuação para capturar a ação, como por exemplo:

Listagem 02: Ponto de atuação da listagem 01


	execution (void Pessoa.salvar(String nome, String sobrenome));

O ponto de atuação “execution” está capturando a execução do método salvar( ), porém se na classe Pessoa tiver outro método salvar( ) sem os mesmos argumentos, o mesmo será desconsiderado pelo ponto de atuação.

Para completar ainda mais o entendimento da aplicação da POA em uma aplicação Java é preciso entender que para cada ponto de junção e ponto de atuação há um adendo (advice), que representa qual código irá executar a cada ponto de junção e ponto de atuação. Dessa forma o programador pode definir quando o código deverá ser executado, se é durante o ponto de junção (around), depois (after) e até mesmo antes do ponto de junção (before).

Listagem 03: Exemplo de execução de ponto de junção com o before()


before() : execution(void salvar(String nome, String sobrenome)){
		System.out.println("Nova pessoa salva!");
	}

Por último o ponto de Inserção (introduction) que permite efetuar mudanças em classes e aspectos do sistema, que provoca mudanças que não alteram diretamente os comportamentos, mas com a inserção é possível adicionar um método à classe, ou até mesmo implementar uma interface.

Listagem 4: Ponto de Inserção, implementando uma interface sem alterar o domínio


declare parents: Pessoa implements PessoaInterface;

Baseado no livro de WINICK e GOETTEN(2006) a aplicação “Olá Mundo” com AspectJ pode ser dada da seguinte forma:

Listagem 5: Código Java com método sobrecarregado


	package br.com.nooclix.aspectos;
public class Comunicador {
	public static void entrega (String mensagem){
		System.out.println(mensagem);
	}	
	public static void entrega(String destino, String mensagem){
		System.out.println(destino + ", "+mensagem);
	}
}

Listagem 6: Código AspectJ criando um ponto de junção a partir de um ponto de atuação


package br.com.nooclix.aspectos;
public aspect AspectoComunicador {
	pointcut entregaMesnagem(): call (* Comunicador.entrega(..));	
	before() : entregaMensagem(){
		System.out.print("Olá);
	}
}

Nas listagens acima observa-se que a declaração de um aspecto é similar a declaração de uma classe. O aspecto define um pointcut chamado entregaMensagem(), que captura as chamadas para todos os métodos com o nome entrega() na classe Comunicador. O símbolo * indica que não importa o tipo de retorno do método e o “..” dentro dos parênteses, após entrega, não faz qualquer especificação quanto ao número de parâmetros e os respectivos tipos. No exemplo apresentado, o pointcut deve capturar chamadas para ambos os métodos sobrecarregados de entrega() na classe Comunicador.

A parte before() indica que o advice deverá ser executado antes da execução do ponto de junção definido no ponto de atuação do adendo – nesse caso, antes da chamada do método Comunicador.entrega(). No adendo, é exibida a mensagem “Olá” sem quebra de linha.

CONCLUSÃO

A POA pode ser vista como solução para as dificuldades encontradas na POO, com o intuito de facilitar o desenvolvimento, manter a coesão e agilizar os processos, tratar a abstração de objetos do mundo real de forma que seja possível a intercomunicação entre os componentes sem interferência no domínio da aplicação, tornando possível a programação nos mais variados contextos.