Reuso da Implementação Orientada a Aspectos do
Padrão de Projeto Camada de Persistência
Copyright © 2004, Ricardo Argenton Ramos™, 1, Valter Vieira de Camargoa, 2
Rosângela Penteado™, Paulo Cesar Masieroa
Permission is granted to copy for the SugarLoafPlop 2004 conference.
All other rights reserved.
™
a
Universidade Federal de São Carlos - Departamento de Computação
Universidade de São Paulo - Instituto de Ciências Matemáticas e de Computação
{rar, rosangel}@dc.ufscar.br, {valter, masiero}@icmc.usp.br
Abstract
This paper relates a reuse experience of the aspect-oriented implementation of the Persistence
Layer pattern in an inventory system that was used as case study. This implementation was
developed in the AspectJ language in a previous work, aiming to separate the functional code from
persistency code. The case study system is implemented in the object-oriented paradigm, in Java,
and uses the Persistence Layer pattern. To reuse the aspect-oriented implementation was necessary
to identify and to remove the object-oriented code of the pattern, what was done by means of
regular expressions. It was noticed that the aspect-oriented reuse process is simpler than the
object-oriented and benefits are perceived in the target system.
Keywords: Aspect-Oriented Reuse, Design Patterns, Persistence Layer.
Resumo
Este artigo relata uma experiência de reuso da implementação orientada a aspectos do padrão
Camada de Persistência em um sistema de controle de estoque utilizado como estudo de caso. Essa
implementação foi desenvolvida, anteriormente, na linguagem AspectJ com o objetivo de separar o
código funcional do código de persistência. O sistema utilizado como estudo de caso está
implementado no paradigma orientado a objetos, com Java, e possui o padrão Camada de
Persistência. Para que a implementação orientada a aspectos do padrão pudesse ser reusada foi
necessário identificar e retirar o código orientado a objetos do padrão, o que foi feito por meio de
expressões regulares. Observou-se que o processo de reuso orientado a aspectos é mais simples do
que o orientado a objetos e benefícios são notados no sistema resultante.
Palavras chave: Reuso Orientado a Aspectos, Padrão de Projeto, Camada de Persistência.
1
2
Apoio Financeiro do CNPq
Apoio Financeiro da CAPES.
1. Introdução
Padrões de Projeto são soluções de projeto já testadas e aprovadas. O reuso dessas soluções
implica em softwares mais manuteníveis e de mais fácil desenvolvimento [5]. Porém,
alguns autores comentam que embora o projeto desses padrões possa ser reutilizado
facilmente, o mesmo não ocorre com a sua implementação, quando ela é Orientada a
Objetos (OO) [6][9]. Da mesma forma, a implementação de requisitos não funcionais
também causa problemas quando é utilizada uma linguagem OO. Como essas linguagens
de programação fornecem mecanismos pouco adequados à implementação de padrões de
projeto e de requisitos não-funcionais [9], permitindo que o código do padrão/requisito nãofuncional permaneça espalhado e entrelaçado com os módulos funcionais da aplicação.
Assim, têm-se problemas de manutenção, evolução e reuso.
Quando ocorre entrelaçamento/espalhamento, uma possível solução é utilizar a
programação orientada a aspectos (POA). Foi proposta em 1997 por Kiczales [7] e visa
fornecer construtores lingüísticos para a separação dos interesses de um sistema em
unidades modulares e posterior composição (weaving) desses módulos em um sistema
completo. Embora padrões de projeto não sejam considerados como requisitos nãofuncionais, sua aplicação muitas vezes faz com que o seu código também se encontre
espalhado/entrelaçado pela aplicação, podendo ser caracterizados como passíveis de serem
implementados com aspectos. Alguns autores têm utilizado a POA na implementação de
padrões de projeto, separando o código do padrão do código funcional [6].
Algumas experiências com o reuso da implementação OO do padrão Camada de
Persistência (Persistence Layer) foram realizadas em trabalhos anteriores [1] [3] [4]. Esse
padrão encapsula o requisito não-funcional de persistência em algumas classes e interfaces
para manter a independência da aplicação. O processo de reuso da implementação OO não
apresenta muitas dificuldades, porém o código que implementa o padrão fica
espalhado/entrelaçado com o código da aplicação, causando os problemas citados
anteriormente.
A implementação desse padrão com a linguagem AspectJ foi realizada por estes
autores [3], e neste artigo será mostrado o processo de reutilização de sua implementação
em um sistema de controle de estoque implementado em Java [4]. Dessa forma, infere-se
que há benefícios alcançados quando se utiliza o processo de reuso da implementação AO.
Ao se notar as implementações OO e AO, observa-se, na segunda, a separação do código
que implementa o padrão, possibilitando uma maior manutenibilidade dos sistemas. Como
o estudo de caso aqui apresentado já continha o padrão Camada de Persistência
implementado de forma OO, expressões regulares foram utilizadas para identificar e
remover o código de persistência [10].
Na Seção 2 encontram-se alguns trabalhos sobre a Programação Orientada a
Aspectos e Padrões de Projeto; na Seção 3 é apresentado o projeto baseado em aspectos do
padrão Camada de Persistência; na Seção 4 são mostrados os detalhes do processo de reuso
realizado e na Seção 5 as considerações finais são apresentadas.
2. Programação Orientada a Aspectos e Padrões de Projeto
Segundo Kiczales e outros [7], a programação orientada a aspectos consiste na separação
dos interesses de um sistema em unidades modulares e posterior composição (weaving)
2
desses módulos em um sistema completo. Esses interesses podem variar de noções de alto
nível, como segurança e qualidade de serviço, a noções de baixo nível, como sincronização
e manipulação de buffers de memória. Eles podem ser tanto funcionais, como
características ou regras de negócio, quanto não-funcionais, como gerenciamento de
transação e persistência.
Aspect/J é uma extensão da linguagem Java, de propósito geral, orientada a
aspectos, em que a principal unidade modular é o aspecto (aspect) [7]. Um aspecto pode
possuir atributos e métodos e participar de uma hierarquia de aspectos por meio da
definição de aspectos especializados. Aspect/J possibilita nomear um conjunto de pontos de
junção e associar uma determinada implementação a eles, que pode ser executada antes,
após ou apropriar-se do fluxo de execução dos eventos relacionados a esses pontos.
Os seguintes conceitos são usados em AspectJ:
Pontos de junção (joinpoints): são métodos bem definidos na execução do fluxo do
programa que compõem pontos de corte.
Pontos de corte (pointcuts): identificam coleções de pontos de junção no fluxo do
programa.
Sugestões (advices): são construções semelhantes a métodos, que definem
comportamentos adicionais aos pontos de junção. São executadas quando pontos de junção
são alcançados [7]. AspectJ tem três tipos diferentes de sugestões:
i) Pré-sugestão (before): é executada quando um ponto de junção é alcançado e
antes da computação ser realizada.
ii) Pós-sugestão (after): é executada quando um ponto de junção é alcançado e após
a computação ser realizada.
iii) Sugestão substitutiva (around): é executada quando o ponto de junção é
alcançado e tem o controle explícito da computação, podendo alternar a execução com o
método alcançado pelo ponto de junção.
A modularização de interesses de entrecorte é realizada usando pontos de junção
(join points) e sugestões (advices).
Segundo Noda e Kishi [9], as técnicas atuais de programação não são adequadas
para a utilização dos padrões de projeto, pois tornam a aplicação dependente deles, o que
diminui as chances de reuso da parte funcional da aplicação. Eles realizaram a
implementação de duas versões de um mesmo sistema utilizando o conceito da separação
avançada de interesses (Advanced Separation of Concern - ASOC) em Aspet/J e Hyper/J,
utilizando o padrão de projeto Observer [5]. Nas duas versões do sistema os autores
separam o código da aplicação do código do padrão, os quais foram tratados como
interesses separados. O interesse que trata da aplicação contém apenas suas funções
específicas, as quais são independentes do padrão, possibilitando o reuso desse interesse. O
interesse que trata do padrão descreve a estrutura e o comportamento abstratos do padrão e
é independente da aplicação.
Assim como Noda e Kishi [9], Hannemann e Kiczales [6] comentam que a técnica
de implementação orientada a objetos não é adequada à implementação de padrões de
projeto. Para testar essa hipótese, realizaram um experimento com programação orientada a
aspectos no qual os vinte e três padrões de projeto propostos por Gamma e outros [5] foram
implementados em Java e em Aspect/J. Os benefícios obtidos em dezessete dos vinte e três
padrões implementados com orientação a aspectos foram: melhor localidade de código,
3
maior reusabilidade, facilidade de composição e de (desc)conectividade entre classes do
padrão e da aplicação. Segundo os autores, alguns padrões possuem estrutura que entrecorta
o relacionamento entre os papéis impostos pelo padrão e as classes de aplicação que
assumem esses papéis. Os três tipos de estruturas identificadas foram as estruturas: de
papéis definidos, de papéis sobrepostos e mista. No primeiro tipo de estrutura o papel é
bem definido, isto é, as classes participantes não têm funcionalidade além daquela
fornecida pelo padrão. Nesses casos a implementação com Aspect/J não apresentou
benefícios. No segundo tipo, os papéis são sobrepostos, isto é, eles são atribuídos a classes
que têm funcionalidade além daquela fornecida pelo padrão. Esse tipo de estrutura foi a que
obteve maiores benefícios, já que a programação orientada a aspectos possui construtores
específicos para tratar relacionamentos de entrecorte. O terceiro tipo de estrutura possui
tanto papéis definidos quanto sobrepostos e também obteve benefícios, porém menores do
que o segundo tipo.
As melhorias obtidas com o uso do Aspect/J são inicialmente devidas à inversão das
dependências. O código do padrão depende dos participantes e não ao contrário, como
ocorre na implementação Orientada a Objetos. Isso possui um impacto direto na localidade
de código, pois todas as dependências entre os padrões e a aplicação são localizadas no
código do padrão.
Visando a necessidade de obtenção de melhorias na localidade do código Orientado
a Objetos, Ramos [10] propõe uma abordagem para migrar sistemas Orientados a Objetos
para sistemas Orientados a Aspectos. Essa abordagem fornece diretrizes e indícios (alguns
no formato de expressões regulares) para a localização, modelagem e implementação de
seis tipos de interesses na linguagem AspectJ.
Com base nos trabalhos apresentados nesta seção nota-se que embora os padrões
não sejam tratados como requisitos não funcionais, sua implementação espalha-se pelo
código funcional, causando problemas de reuso, manutenção e evolução. Com base nessa
motivação, o padrão Camada de Persistência [11] foi implementado com aspectos [3] e essa
implementação é apresentada com maiores detalhes na próxima Seção.
3. Projeto Baseado em Aspectos do Padrão Camada de Persistência
O padrão de projeto Camada de Persistência permite minimizar a incompatibilidade
existente entre o paradigma orientado a objetos e a persistência de dados em um banco
relacional [11]. Ele consiste em uma camada que cuida da interface entre objetos de
aplicação e tabelas de banco de dados relacional. Possui um conjunto de dez sub-padrões
que podem ser utilizados para a implementação dessa camada de persistência: Camada
Persistente (Persistent Layer), CRUD (Criação (Create), Leitura (Read), Atualização
(Update) e Remoção (Delete)), Descrição de Código SQL (SQL Code Description),
Gerenciador de Tabelas (Table Manager), Métodos de Mapeamento de Atributos (Atributte
Mapping Methods), Conversão de Tipos (Type Conversion), Gerenciador de Mudanças
(Change Manager), Gerenciador de Identificadores Únicos (OID Manager), Gerenciador
de Conexão (Connection Manager) e Gerenciador de Transação (Transaction Manager).
Cada um deles possui uma funcionalidade bem definida e enquanto alguns são obrigatórios,
outros são opcionais. Por exemplo, o padrão CRUD é essencial, para a realização das
operações básicas de persistência, já o padrão Conversão de Tipos é útil, mas não essencial,
podendo não ser utilizado.
4
O padrão Camada de Persistência possui três formas de uso, segundo Cagnin [1] a
terceira forma é a que permite mais facilmente reutilizar o Gerenciador de Tabelas (Table
Manager), pois não há preocupação com a persistência de qualquer tipo de objeto no banco
de dados, necessitando apenas conhecer os parâmetros dos métodos das classes. Além
disso, o sistema implementado utilizando-a é o mais manutenível. Embora a classe
TableManager seja reusável, o mesmo não ocorre com as classes da aplicação, devido à
dependência do padrão, que ocorre porque essas classes invocam métodos existentes nas
classes que implementam o padrão.
Camargo e outros [3] fornecem uma alternativa de projeto baseado em aspectos para
este padrão que pode ser reutilizada em aplicações específicas. O objetivo foi desenvolver
uma estrutura que mantivesse separado o código de persistência do código funcional,
facilitando dessa forma o entendimento do padrão e melhorando sua reusabilidade. Para
isso, um estudo de caso com um sistema de oficina eletrônica implementado em Java e
reimplementado em AspectJ foi utilizado para comparar as duas alternativas de
implementação. A versão do padrão com aspectos manteve o código de persistência
completamente separado do código funcional, facilitando o entendimento e,
conseqüentemente, a sua manutenibilidade e o reuso. Neste artigo é mostrada a experiência
em reutilizar o código do padrão Camada de Persistência baseado em aspectos em um
sistema de controle de estoque.
A Figura 1 mostra uma instanciação genérica do projeto baseado em aspectos do
padrão Camada de Persistência [3], sendo que na parte superior encontra-se a camada de
persistência e na inferior, a camada de aplicação. Ressalta-se que o termo “instanciação”
está sendo usado para evidenciar que algumas partes do projeto baseado em aspectos do
padrão precisam ser modificadas de acordo com a aplicação na qual ele será acoplado.
Contudo, há consciência de que esse projeto não é um framework. Outro ponto que merece
destaque é que a notação usada neste diagrama para representar os conceitos da POA é a
proposta por Camargo e Masiero [2], que evoluiu a partir da necessidade de se representar
os conceitos básicos da POA e também de frameworks orientados a aspectos.
O aspecto abstrato AbstractAspectConnection encapsula o comportamento
genérico de conexão com o banco de dados e deve ser especializado por um aspecto
concreto que especifica detalhes específicos da aplicação. Esses detalhes consistem na
sobreposição de alguns métodos abstratos e também na especificação de dois pontos de
corte abstratos, que podem ser identificados pelos estereótipos <<pointcut-hook>> em
itálico. A identificação dos pontos de instanciação é feita por meio da existência do
conceito de gancho (hook). Por exemplo, o ponto de corte openConnection() é um
gancho e precisa ser redefinido no aspecto especializado. Da mesma forma, os métodos
com estereótipo <<hook>> também são pontos de instanciação que precisam ser
redefinidos. A sobreposição dos métodos é feita para informar detalhes da conexão,
enquanto que a especificação do ponto de corte concreto é feita para indicar em que ponto
da aplicação a conexão deve ser feita. Note-se que a existência dos pontos de corte é o que
determina a independência da aplicação em relação ao código não-funcional, pois na
implementação OO, o ponto da aplicação onde a conexão deve ser aberta contém uma
chamada a algum método da camada de persistência. Na implementação OA o que ocorre é
o contrário, a camada de persistência tem consciência dos locais onde a conexão deve ser
5
aberta. Essa inversão de dependência é o ponto fundamental que mantém a aplicação livre
do código não-funcional.
<<aspect>>
AbstractAspectConnection
<<pointcut-hook>> closeConnection()
<<pointcut-hook>> openConnection()
<<after>> closeConnection()
<<after>> openConnection()
<<hook>> setJDBC()
<<hook>> execute()
<<hook>> executeQuery()
<<hook>> conectDB()
<<hook>> closeDB()
<<aspect>>
AspectStructure
<<introduction>>
{method = findAll(), getLast(), findLike(), delete()}
TableManager
<<aspect>>
AspectConnection
{attribute = tableName, keyName, colNames,
colValues, cols}
<<aspect>>
AspectClasseApp
<<pointcut>> openConnection()
<<pointcut>> closeConnection()
<<after>> changesConstructor()
<<after>> changesEmptyConstructor()
Camada de Persistência
Camada de Aplicação
<<crosscutting>>
{joinPoint = ?ClasseAplicacao(..)}
{PCDescriptor = changesConstructor()}
<<crosscutting>>
{joinPoint = ? ClasseAplicacao()}
<<introduction>>
{method = save(), getPrimaryKeyClause()
{PCDescriptor = changesEmptyConstructor()} getPrimaryKeyValue()}
ClasseAplicacao
Figura 1 – Projeto Baseado em Aspectos do Padrão Camada de Persistência.
Na
Figura
1,
os
dois
pontos
de
corte
abstratos
do
aspecto
AbstractAspectConnection e também os métodos abstratos são redefinidos no aspecto
concreto AspectConnection, porém apenas o ponto de corte concreto
openConnection() e closeConnection() está sendo exibido.
A classe TableManager não foi transformada em aspectos porque seu
comportamento já estava bem encapsulado e ela não influenciava nenhuma das classes de
aplicação. Sendo assim, optou-se por não transformá-la em aspecto.
O aspecto AspectStructure é responsável por introduzir nas classes de aplicação
alguns atributos e métodos de persistência independentes de qualquer aplicação. Embora
não seja explícito no diagrama, o ponto de instanciação nesse aspecto consiste em informar
em quais classes de aplicação esses atributos e métodos devem ser inseridos. Na Figura 1,
isso é representado por meio de um relacionamento de introdução, representado com o
estereótipo <<introduction>>. Os atributos e métodos de persistência que serão inseridos na
classe de aplicação ClasseAplicacao podem ser vistos por meio das etiquetas valoras
(tag values) attribute e method, respectivamente. Na implementação OO, esses atributos e
métodos estão presentes e repetidos em todas as classes de aplicação.
6
O aspecto AspectClassApp é um tipo de aspecto dependente de uma determinada
classe persistente de aplicação. Ele é responsável tanto por inserir alguns métodos nessa
classe, quanto por interceptar as execuções do construtor para modificar seu
getPrimaryKeyClause(),
comportamento.
Por
exemplo,
os
métodos
getPrimaryKeyValue() e o save(), vistos por meio da etiqueta method do
relacionamento de introdução entre o aspecto AspectClassApp e a classe
ClasseAplicacao, possuem informações dependentes dessa classe, que devem ser
informadas dentro do aspecto. Além disso, deve-se notar também dois relacionamentos de
interceptação (crosscutting) desse aspecto com essa classe. O primeiro utiliza o ponto de
corte changesConstructor() para interceptar as execuções do construtor normal da
classe ClasseAplicacao. Essas informações podem ser obtidas analisando-se as
etiquetas PCDescriptor e joinPoint do relacionamento de interceptação em questão. O
segundo
relacionamento
de
interceptação
utiliza
o
ponto
de
corte
changesEmptyConstructor() para interceptar as execuções do construtor vazio dessa
mesma classe. Após essas interceptações, as sugestões existentes nesse aspecto informam
detalhes específicos da aplicação.
A Seção seguinte apresenta o estudo de caso realizado para avaliar o reuso da
implementação do padrão de projeto Camada de Persistência implementado com aspectos.
4. Estudo de Caso
O estudo de caso consiste em um sistema de controle de estoque implementado na
linguagem Java que utiliza o banco de dados relacional SyBase e HTML para as interfaces.
O padrão Camada de Persistência está implementado no paradigma Orientado a Objetos
(OO) para separar o código da aplicação do código da persistência. A comunicação entre o
banco de dados e as interfaces foi implementada por meio de servlets [4]. A função
principal do sistema é cadastrar materiais, fornecedores, contas, previsão de compras e
alguns documentos, como por exemplo, requisição de material, solicitação de material,
comunicado de recebimento, devolução de materiais ao fornecedor, correção de estoque
físico, etc.
Como o padrão foi implementado utilizando o paradigma OO, todas as classes
persistentes da aplicação contêm o código de persistência entrelaçado e espalhado pelos
módulos funcionais.
A Figura 2 mostra esquematicamente as atividades realizadas. A Atividade I é
apoiada por expressões regulares, que fornecem os indícios para o engenheiro de software
encontrar o interesse de persistência [10], e tem como entrada o código fonte do sistema de
controle de estoque implementado no paradigma OO. O código fonte marcado com
comentários, quando o interesse é localizado, e a implementação em aspectos do padrão de
projeto Camada de Persistência [3], são as entrada para a Atividade II. A seguir são
descritas as atividades que foram realizadas.
7
Código fonte OO do
sistema de Controle de
Estoque
Atividade I
Identificar o código que
implementa o padrão Camada
de Persistência.
Código fonte OO do sistema de
Controle de Estoque com os trechos
de código marcados.
Expressões
Regulares
Código fonte OA do Padrão
Camada de Persistência
Atividade II
Reutilizar a porção de código
genérica e adaptar a porção de
código especifica do padrão.
Código fonte OA do
sistema de Controle de
Estoque
Figura 2 - Atividades do processo de reuso do padrão Camada de Persistência.
4.1. Atividade I: Identificar o Código Fonte que Implementa o Padrão Camada de
Persistência
Essa atividade utiliza as expressões regulares criadas na abordagem Aspecting [10] para
identificar interesses existentes no código fonte OO. A Figura 3 mostra a expressão regular
referente ao interesse de Persistência que está presente no código fonte do sistema de
Controle de Estoque. Todo trecho de código reconhecido por essa expressão regular deve
ser considerado como sendo do interesse de persistência e deve-se adicionar, ao final de
cada linha, comentários que indiquem que esta linha pertence ao interesse. Esse recurso de
comentários também proposto na abordagem Aspecting.
<i.Persistencia.BD> = ‘Connection’ <statements> |
‘Connection’ <statements> <SQL>|
<SQL> <statements> ‘Connection’|
‘PreparedStatement’ <statements>|
‘PreparedStatement’ <statements> <SQL>|
<SQL> <statements> ‘PreparedStatement’|
‘ResultSet’ <statements>|
‘ResultSet’ <statements> <SQL>|
<SQL> <statements> ‘ResultSet’
Figura 3 - Expressão regular que auxilia a identificar os indícios do interesse de Persistência [10].
As expressões regulares existentes para reconhecer os indícios de Persistência não
foram elaboradas considerando a utilização do padrão Persistence Layer. Assim, no trecho
de código da classe Conta, apresentado na Figura 4, somente a parte marcada com (a) é
que foi reconhecida como de Persistência. Os outros trechos de código, (b) e (c), foram
reconhecidos pelo engenheiro de software como parte do padrão. Para isso há necessidade
do conhecimento da granularidade3 do padrão Camada de Persistência.
3
O quanto e como está espalhada pelas classes a implementação do padrão.
8
public class Conta implements PersistentObject
{
. . .
private TableManager tablemanager;
private String tableName;
. . .
colNames.addElement ("codigo");
colNames.addElement ("descrição");
. . .
public boolean save ()
{ ResultSet rs; // Persistência
Vector clause = new Vector();
Vector parameter = new Vector(); . . .
}
(c)
(b)
Atributos não localizados pela
expressão regular, porém que
fazem parte do interesse de
Persistência.
(a)
Linha de código reconhecida
pela expressão regular como
sendo do Interesse de
Persistência
Figura 4 - Trecho de código da classe Conta.
4.2. Atividade II: Reutilizar a Porção de Código Genérica e Adaptar a Porção de
Código Especifica do Padrão
A Figura 5 mostra as três etapas para a execução dessa atividade: (1) análise e adaptação
para o reuso dos aspectos AbstractAcpectConnection, AspectConnection que
implementam o sub padrão Gerenciador de Conexão; (2) análise e adaptação para o reuso
do aspecto AspectStructure que implementa parte dos sub padrões Gerenciador de
Tabelas, CRUD e Objeto Persistente; e (3) análise e adaptação/criação para o reuso dos
aspectos que implementam atributos específicos de persistência para cada classe de
aplicação. Os aspectos dessa última etapa implementam o sub padrão Métodos de
Mapeamento de Atributos e a parte restante dos sub padrões CRUD e Objeto Persistente.
Nessa etapa é reutilizada a implementação da classe TableManeger.
Após a aplicação das três etapas a camada de persistência reusada, Figura 5 (a),
intercepta a camada de aplicação do sistema de Controle de Estoque, Figura 5 (b).
(a) Camada de
<<aspect>>
AbstractAspectConnection
<<pointcut-hook>> closeConnection()
<<pointcut-hook>> openConnection()
<<after>> closeConnection()
<<after>> openConnection()
<<hook>> setJDBC()
<<hook>> execute()
<<hook>> executeQuery()
<<hook>> conectDB()
<<hook>> closeDB()
Persistência Reusada
(b) Camada de Aplicação
do Sistema de
Controle de Estoque
<<aspect>>
AbstractAspectConnection
Estoq
<<pointcut-hook>> closeConnection()
<<pointcut-hook>> openConnection()
<<after>> closeConnection()
<<after>> openConnection()
<<hook>> setJDBC()
<<hook>> execute()
<<hook>> executeQuery()
<<hook>> conectDB()
<<hook>> closeDB()
(1)
estoq
almoxarif
Localiza
deposi
pratelei
repartic
Cont
bo
descric
setObje
()
setDBtoObj
debito
credito
debitoM
credito
conta
conta
<<pointcut>> openConnection()
conta
<<pointcut>> closeConnection()
<<aspect>>
MesAt
<<pointcut>> openConnection()
<<pointcut>> closeConnection()
(2)
<<aspect>>
AspectStructure
AnoAt
MovimentoMesesAn
quantidadeNaoAt
quantidadeNaoAt
me
setObje
()
setDBtoObj
()
setObje
()
setDBtoObj
()
setObje
()
setDBtoObj
()
1
AspectStructure
Materi
codig
class
descric
unida
maxM
maxi
TableManager
mini
qtdEstoq
Movime
t
quantidade
quantidad
S
valorEn
valorS
TableManager
precoMe
sald
valorUltimaCo
valorCompr
C
compraUnitariaForn
dataUltimoMovi
dataCada
<<aspect>>
AspectClasseApp
<<after>> changesConstructor()
<<after>> changesEmptyConstructor()
setObje
()
setDBtoObj
(3)
<<aspect>>
AspectClasseApp
<<after>> changesConstructor()
<<after>> changesEmptyConstructor()
Figura 5 - Etapas realizadas no processo de reuso do padrão de projeto Camada de Persistência.
9
Na etapa (1), apenas o aspecto AbstractAspectConnection, mostrado na Figura 6,
é reusado completamente sem adaptações para o sistema de controle de estoque. Ele possui
um ponto de corte abstrato denominado openConnection(), cujo ponto de junção deve ser
fornecido pelo aspecto, mostrado na Figura 7, AspectConnection que é o aspecto concreto
que o especializa.
public abstract aspect AbstractAspectConnection
{
public static Connection con;
public static Statement stmt;
...
abstract pointcut openConnection();
after() : openConnection()
{...
ConnectDB(); } ...
public
void
setJDBC(...)
protected static void
ConnectDB ()
private
static void
CloseDB ()
public
static void
execute()
public
static ResultSet executeQuery()
}
{...}
{...}
{...}
{...}
{...}
Figura 6 - Aspecto de Conexão Abstrato.
Para o AspectConnection é necessário que se defina o ponto de junção concreto,
que indica o método que deve ser interceptado para realizar a conexão, e também os
parâmetros de configuração dessa conexão na Sugestão before. A parte (a) na Figura 7
mostra que o ponto de junção concreto são chamadas do método init(), pois é nesse local
do código da implementação orientada a objetos que havia uma chamada ao método
responsável pela conexão com o banco de dados. Além disso, na Sugestão before desse
aspecto, o método setJDBC() deve ser invocado do aspecto abstrato passando alguns
parâmetros de configuração necessários à conexão, conforme apresentado na parte
destacada com a letra (b) dessa mesma figura. Portanto para a adaptação desse aspecto em
(a) indicou-se o método que era chamado na versão OO, após a conexão com o banco de
dados. Em (b) foram adicionados o nome do banco de dados, nome do usuário desse banco
e a senha. Foram retirados das classes de aplicação, todos os métodos referentes a conexão
que estavam marcados como sendo do padrão.
public aspect AspectConnection extends AbstractAspectConnection
{
pointcut doConnection(): call (void init(..));
(a)
}
Ponto de junção fornecido
before() : doConnection()
{
super.setJDBC("jdbc:odbc:estoque", "DBA", "sql",...);
(b)
}
Parâmetros de
configuração
Figura 7 - Aspecto de Conexão Concreto.
Na etapa (2), o AspectStructure, mostrado na Figura 8, é adaptado para poder ser
reutilizado. Esse aspecto por meio do conceito de Introduções, insere os atributos de
persistência tableName, keyName, colNames, colValues, colNamesException e cols em
todas as classes de aplicação, pois são atributos provenientes do sub-padrão Gerenciador de
10
Tabelas. O mesmo ocorre com os métodos findAll() e findLike(), que foram
reusados do sub-padrão Objeto Persistente e, delete() que foi reusado tanto do Objeto
Persistente quanto do CRUD. Portanto para a adaptação desse aspecto para o reuso foi
necessário adicionar o nome de todas as classes de aplicação do sistema de Controle de
Estoque juntamente com os métodos e atributos descritos a cima. A Figura 8 ilustra em
negrito, alguns trechos dessa adaptação para a classe Conta. Foram retirados das classes de
aplicação todos os métodos e atributos marcados como sendo do padrão que estavam
relacionados no aspecto AspectStructure.
public aspect AspectStructure
{
private String Conta.tableName;
. . .
private String Conta.keyName;
. . .
private String Conta.colNames = new Vector();
. . .
private String Conta.colNamesException = new Vector();
... métodos sets e gets
public ResultSet Conta.findall ()
{ return TableManager.findallDB(this.getTableName()); }
public ResultSet Conta.findlike ()
{...} . . .
public boolean Conta.delete () {...} }. . .
}
Figura 8 - Aspecto AspectStructure.
A etapa (3) consiste em criar um aspecto para cada classe persistente de aplicação.
A Figura 9 apresenta o aspecto AspectConta, que possui comportamento específico para a
classe Conta, pois deve definir valores de persistência para essa classe, tais como: nome da
tabela, nome das colunas da tabela, nome da chave primária e número de colunas, como
mostrado parcialmente na parte destacada com a letra (a). A parte destacada com a letra (b)
mostra a atribuição dos valores para os atributos definidos anteriormente. Como esse tipo
de aspecto possui características específicas de cada classe de persistência, foi criado um
aspecto como esse para cada uma delas. O ponto de corte changesConstructor() desse
aspecto possui como tarefa interceptar chamadas do construtor da classe Conta e definir
valores para os atributos de persistência dessa classe. Foram retirados das classes de
aplicação todos os métodos e atributos marcados como sendo do padrão que estavam
relacionados aos aspectos específicos.
public aspect AspectConta
{
pointcut changesConstructor(Conta c): target (c) && execution
(Conta.new(int, String, String, String, String, String, String));
after (Conta c): changesConstructor(c)
{c.setTableName("Conta");
(a)
c.setKeyName("codigo");
. . .
id = new Integer(c.getCodigo());
c.setColValues(id);
(b)
c.setColValues(c.getDescricao());
. . .}
public boolean Conta.save () { . . . }
public Conta Conta.SetObject (ResultSet rs) { . . . }
private Conta Conta.SetDBToObject(ResultSet rs) { . . . }
}
Figura 9 - Aspecto AspectConta.
11
A Tabela 1 apresenta para cada aspecto reusado, quais foram as ações efetuadas
para reusar o código na versão Orientada a Aspectos (OA) e quais seriam as ações
necessárias para reusar a porção de código equivalente na versão Orientada a Objetos (OO).
Tabela 1 - Comparação das adaptações para o reuso nas versões OO e OA.
Aspectos Reusados
Ações necessárias para reusar na versão
orientada a aspectos
AbstractAspectConnection 1 - especificar um ponto de corte no
AspectConnection
e AspectConnection
2 - sobrepor o método setJDBC()
inserindo as informações especificas sobre
a conexão.
AspectStructure
Aspectos específicos e a classe
TableManeger
Ações necessárias para reusar na
versão orientada a objetos
1 - sobrepor as informações
específicas sobre a conexão na classe
ConnectionManneger.
2 - procurar por todos os “pontos” da
aplicação que fazem a conexão com o
banco de dados.
1 - alterar o aspecto AspectStructure 1 - procurar por todas as classes que
colocando o nome das classes que fazem a fazem a persistência e adicionar os
atributos e métodos.
persistência.
1 - criar um aspecto para cada classe de
persistência da aplicação.
2 - utilizar o conceito de introdução e
adicionar três métodos que pertencem ao
padrão nas classes que fazem a
persistência.
3 - criar dois pontos de corte e duas
sugestões (advices) que modificam os
construtores
4 - reutilizar a classe TableManeger
sem modifica-la.
1 - procurar por todas as classes que
fazem a persistência e adicionar os
métodos que pertencem ao padrão.
2 - alterar os construtores das classes
que fazem a persistência.
3 - reutilizar a classe
TableManeger sem modifica-la.
A partir da comparação das ações necessárias para a reutilização da implementação
do padrão de projeto Camada de Persistência observados na Tabela 1 é possível inferir que
apesar de ter mais ações realizadas na versão Orientada a Aspectos são menos trabalhosas
que as para realizar o reuso na versão Orientada a Objetos. Ações como procurar por
“pontos” da aplicação que necessitam fazer a conexão como o banco de dados, despendem
muito mais tempo do que a ação de especificar a captura desses “pontos” em um ponto de
corte.
5. Considerações Finais
Este artigo mostra uma experiência de reuso da implementação orientada a aspectos do
padrão Camada de Persistência em um sistema de controle de estoque. Como os autores já
tinham experiência em reusar a implementação orientada a objetos desse padrão em outros
sistemas, foi possível identificar que o processo de reuso orientado aspectos possui um
número maior de passos, porém são mais simples do que os passos do reuso orientado a
objetos.
Note-se que no contexto do estudo de caso realizado não foi considerado o
conhecimento do engenheiro de software com programação orientada a aspectos.
Os benefícios ou vantagens observados com o reuso do padrão implementado com
aspectos foram:
• Facilidade de manutenção - Como o código fica mais modular e com menos
redundâncias, o engenheiro de software não necessita procurar os trechos de código do
padrão por todas as classes de aplicação, pois ele está localizado em poucos módulos;
12
• Facilidade de compreensão do código - Da mesma forma que o tópico anterior, a
modularidade faz com que o engenheiro de software se concentre em poucos módulos para
entender a persistência;
• Facilidade de evolução - Como o código do padrão encontra-se bem modularizado,
adicionar novos aspectos que tratam de outros interesses se torna mais fácil. Por exemplo,
poderia ser adicionado um novo aspecto que cuidasse do interesse de geração de
identificador automaticamente.
Embora o padrão Camada de Persistência tenha se mostrado adequado para ser
implementado com aspectos, não são todos os padrões de projeto que apresentam esse
comportamento. Alguns dos padrões propostos por Gamma e outros [5] ficam mais
complexos do que se estivessem implementados no paradigma Orientado a Objetos [9].
A utilização das expressões regulares [10] auxiliou a identificação do interesse de
persistência, porém foi necessário o conhecimento da granularidade da implementação do
padrão Camada de Persistência, pois as heranças e implementações de interfaces não
estavam previstas na expressão regular. A elaboração de expressões regulares que
reconheçam trechos de código relativos ao padrão deverá também ser incorporadas na
abordagem Aspecting.
A implementação do padrão Camada de Persistência com aspectos [2] já evoluiu
bastante e já pode ser considerado como um framework de persistência orientado a
aspectos. Infere-se que a utilização de um framework de persistência seja uma solução mais
eficaz para o reuso do interesse de persistência.
6. Referências Bibliográficas
[1]
Cagnin, M.I. Avaliação das Vantagens quanto à Facilidade de Manutenção e
Expansão de Sistemas Legados Sujeitos à Engenharia Reversa e Segmentação.
Dissertação de Mestrado, DC-UFSCar, 1999.
[2]
Camargo, V.V. Masiero, P.C. UML-AOF – Um Perfil UML para o Projeto de
Frameworks Orientados a Aspectos. Relatório Técnico, ICMC-USP, 2004.
Disponível para download em: http://www.icmc.usp.br/~valter/publicacoes.
[3]
Camargo, V.V.; Ramos, R.A.; Penteado, R.A.D.; Masiero, P.C. Projeto Baseado em
Aspectos do Padrão Camada de Persistência. In: Simpósio Brasileiro de
Engenharia de Software (SBES), Manaus, 2003.
[4]
Camargo, V.V. Reengenharia Orientada a Objetos de Sistemas COBOL com a
utilização de Padrões de Projeto e Servlets. Dissertação de Mestrado,
Departamento de Computação da Universidade Federal de São Carlos, 2001.
[5]
Gama, E., Helm, R., Johnson, R., Vlissides, J. Design Patterns: Elements of
Reusable Object-Oriented Software. Addison-Wesley, 1995.
[6]
Hannemann and Kiczales. Design Pattern Implementation in Java and AspectJ,
Proceedings of the 17th Annual ACM conference on Object-Oriented
Programming, Systems, Languages, and Applications (OOPSLA), pages 161-173,
November 2002.
13
[7]
Kiczales, G.; Hilsdale, E.; Hugunin, J.; Kersten, M.; Palm, J. Griswold, W.G.
Getting Started with AspectJ. In: Anais do ACM, pág. 59-65, Outubro 2001.
[8]
Kiczales, G.; Lamping, J.; Mendhekar, A. RG: A Case-Study for Aspect-Oriented
Programming. Artigo Técnico, SPL97. Xerox Palo Alto Research Center, 1997.
[9]
Noda, N. and Kishi, T. "Implementing Design Patterns Using Advanced Separation
of Concerns", in Proceedings of OOPSLA 2001, Workshop on Advanced
Separation of Concerns in Object-Oriented Systems, Tampa Bay, FL, October
2001.
[10]
Ramos, R., A. Aspecting: Abordagem para Migração de Sistemas OO para Sistemas
AO. Dissertação de Mestrado. Programa de Pós Graduação em Ciência da
Computação, Universidade Federal de São Carlos, São Carlos - SP, maio de 2004.
[11]
Yoder, J. W.; Johnson, R. E.; Wilson, Q. D. Connecting Business Objects to
Relational Databases. Conference on the Pattern Languages of Programs, 1998.
14
Download

Reuso da Implementação Orientada a Aspectos do Padrão