E possvel, ainda, denir regras after para serem executadas ap os o retorno normal
de um m etodo, utilizando-se para isso a construc ao after returning. Para denir regras a
serem executadas em caso de retorno com lancamento de excec ao, utiliza-se a construc ao
after throwing.
Por exemplo, a regra after do programa anterior pode ser reescrita como:
after() returning (): loggableCalls() {
Logger.doExit(thisJoinPoint.getSignature() + " with normal return");
}
after() throwing (Exception exc): loggableCalls() {
Logger.doExit(thisJoinPoint.getSignature() + " with " + exc + " thrown");
}
A primeira regra indica que deve ser feito o registro do retorno normal do m etodo
no ponto de junc ao. A segunda regra indica que, se a sada do m etodo foi feita por um
lancamento de excec ao, ent ao o registro da sada deve exibir a excec ao lancada.
Regras podem ser parametrizadas. Por exemplo, as regras after no trecho de
c odigo a seguir imprimem valores passados como par ametro para setX ou retornados
de getX.
pointcut settingX(int val): execution(void Point.setX(int)) && args(val);
pointcut gettingX(): execution(int Point.getX());
after(int val): settingX(val) {
System.out.println("Value assigned to x: " + val);
}
after() returning (int val): gettingX() {
System.out.println("Value of x: " + val);
}
Uma regra around envolve um ponto de junc ao e dene se a execuc ao deve prosse-
guir normalmente, ou com uma lista de par ametros diferente, ou ainda se outra operac ao
deve ser realizada sem a execuc ao do ponto de junc ao. A regra around dene tamb em
um tipo de retorno, de modo que e possvel especicar um valor de retorno diferente do
obtido na execuc ao do ponto de junc ao.
21
O exemplo a seguir mostra o uso de regras around para garantir os limites do
valor de x na classe Point. O conjunto de junc ao capturado e o conjunto das chamadas do
m etodo Point.setX. Na regra, testa-se o valor de x. Se este for v alido, ent ao a execuc ao do
ponto de junc ao continua normalmente com o valor passado. Caso contr ario, a excec ao
IllegalArgumentException e lancada.
void around(Point p, int x) : target(p) && args(x) && call(void setX(int)) {
if (x >= 0 && x < 100)
proceed(p, x);
else
throw new IllegalArgumentException();
}
4.2.6. Aspectos
Um aspecto e uma unidade modular de implementac ao de requisitos transversais. Aspec-
tos s ao denidos por declarac oes de aspectos, que s ao similares a declarac oes de classes
em Java. Declarac oes de aspectos podem declarar conjuntos de junc ao e regras, incluir
m etodos e campos e podem estender classes ou outros aspectos.
Ao contr ario de classes, aspectos n ao podem ser instanciados. Para obter re-
fer encia a um aspecto, utiliza-se o m etodo est atico aspectOf(), presente em todos os as-
pectos.
Para ilustrar, o exemplo a seguir mostra a declarac ao do aspecto LoggingAspect,
que dene os conjuntos de junc ao publicMethods, logObjectCalls e loggableCalls, e regras
after e before para loggableCalls.
public aspect LoggingAspect {
pointcut publicMethods(): execution(public * *(..));
pointcut logObjectCalls() : execution(* Logger.*(..));
pointcut loggableCalls() : publicMethods() && ! logObjectCalls();
before(): loggableCalls() {
Logger.logEntry(thisJoinPoint.getSignature().toString());
}
after(): loggableCalls() {
Logger.logExit(thisJoinPoint.getSignature().toString());
}
}
O controle de visibilidade de membros de aspectos em AspectJ e igual ao controle
de visibilidade de membros de classes em Java, sendo possvel utilizar os modicadores
public, private ou protected, ou ainda denir visibilidade de pacotes, se nenhum dos
tr es modicadores for utilizado.
Aspectos podem ser estendidos ou especializados, sendo neste caso denominados
subaspectos, formando uma hierarquia de aspectos. N ao e permitida a denic ao de hie-
rarquias m ultiplas de aspectos. As regras para redenic ao de conjuntos e regras de junc ao
em subaspectos s ao similares ` as regras de redenic ao de m etodos em Java.
22
Um aspecto pode ser abstrato, ou pode possuir conjuntos de junc ao abstratos.
A sem antica de conjuntos de junc ao abstratos e semelhante a de m etodos abstratos: as
decis oes de implementac ao s ao adiadas para aspectos concretos que estendam aspectos
abstratos. O exemplo da Sec ao 5.4 mostra uma implementac ao de aspecto e conjunto de
junc ao abstratos.
Em AspectJ, e possvel ainda declarar conjuntos est aticos de junc ao dentro de
classes. Entretanto, n ao e permitido a uma classe declarar regras; apenas aspectos podem
conter regras. Aspectos internos a classes devem ser est aticos, pois n ao pertencem ` as suas
inst ancias. Por exemplo, a classe a seguir dene um aspecto est atico interno SetterEn-
forcement, que obriga o uso dos m etodos setX e setY em todos os pontos do programa,
evitando acesso direto aos campos x e y exceto nos corpos dos m etodos de alterac oes (ver
Sec ao 4.2.7).
public class Point {
private int x, y;
public Point(int x, int y) { this.x = x; this.y = y; }
public int getX() { return x; }
public int getY() { return y; }
public void setX(int x) { this.x = x; }
public void setY(int y) { this.y = y; }
static aspect SetterEnforcement {
declare error: set(int Point.*) && !withincode(void Point.set*(int)):
"Use setter method, even inside Point class.";
}
}
4.2.7. Transversalidade Est atica
Algumas implementac oes de aspectos, como por exemplo a implementac ao de padr oes de
projeto, necessitam de recursos para alterar tanto o comportamento das classes em tempo
de execuc ao, quanto a sua estrutura est atica.
A transversalidade din amica, obtida a partir de regras de junc ao, permite modi-
car o comportamento da execuc ao do programa, ao passo que a transversalidade est atica
permite redenir a estrutura est atica dos tipos classes, interfaces ou outros aspectos e
o seu comportamento em tempo de execuc ao.
EmAspectJ, e possvel implementar os seguintes tipos de transversalidade est atica:
(i) introduc ao de campos e m etodos em classes e interfaces; (ii) modicac ao da hierarquia
de tipos; (iii) declarac ao de erros e advert encias de compilac ao; (iv) enfraquecimento de
excec oes.
Introduc ao de Campos e M etodos em Classes e Interfaces
A linguagem AspectJ possui um mecanismo denominado introduc ao, que permite
a inclus ao de atributos e m etodos em classes ou interfaces de forma transversal.
E possvel
tamb em adicionar campos e m etodos n ao-abstratos em implementac oes de interfaces de
Java, permitindo adicionar um comportamento default ` as classes que as implementem.
Isto permite que o desenvolvedor evite duplicidade de c odigo em cada classe, visto que
tal adic ao informa ao compilador de aspectos que este c odigo deve ser includo nas classes
que implementem as interfaces.
23
Sem AspectJ, a estrat egia usual consiste na criac ao de uma classe com a im-
plementac ao default da interface, de modo que uma classe que implemente a interface
possa ser denida como subclasse da classe com a implementac ao default. Por exem-
plo, a classe MouseAdapter e uma implementac ao default da interface MouseListener,
fornecendo uma implementac ao vazia para cada um dos seus m etodos. Uma classe que
precisar, por exemplo, denir somente o comportamento do m etodo mouseClicked pode
estender esta classe, sem a necessidade de implementar os demais m etodos. Entretanto,
isto s o pode ser utilizado se a classe n ao precisar estender outra classe do programa. O
uso simplesmente de classes abstratas no lugar de interfaces impede o re uso de outras
classes via heranca. Este problema pode tamb em ser resolvido por meio de composic ao.
Entretanto, esta soluc ao consiste na implementac ao de diversos m etodos de uma unica
linha, dando origem a espalhamento.
Por exemplo, considere a interface a seguir cujo objetivo e modelar entidades que
possam possuir um nome:
public interface Nameable {
public void setName(String name);
public String getName();
}
Cada classe que implementa esta interface deve denir os seus dois m etodos, como
no exemplo a seguir:
public class Entity implements Identiable, Nameable {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
C odigo semelhante deve ser inserido em todas as classes que implementarem esta
interface. Para evitar esta duplicidade de c odigo, e possvel denir um aspecto que in-
troduza a implementac ao default dos m etodos para a interface. Para incluir atributos e
m etodos em interfaces e classes em Java, qualica-se o seu nome com o nome da classe
ou interface onde ser a inserido, seguido de um ponto.
public interface Nameable {
public void setName(String name);
public String getName();
static aspect DefaultImplementation {
private String Nameable.name;
public void Nameable.setName(String name) {
this.name = name;
}
public String Nameable.getName() {
return name;
}
}
}
Com esta nova implementac ao, as classes que implementam a interface Nameable
24
n ao precisam mais denir os m etodos, se a implementac ao default estiver adequada para
a classe. Se alguma classe que implementa uma interface com comportamento default
precisar personalizar algum m etodo, basta fazer a sua implementac ao direta, pois estes
ir ao redenir a implementac ao default introduzida no aspecto.
A nova vers ao da classe Entity e mostrada a seguir:
public class Entity implements Identiable, Nameable {
}
A soluc ao tradicional de Java consiste em criar uma classe DefaultNameable, con-
tendo as implementac oes default. A classe Entity deve ser, portanto, subclasse de Default-
Nameable. Entretanto, esta abordagem funciona adequadamente somente para a imple-
mentac ao de uma unica interface. Considere, por exemplo, a interface Identiable denida
a seguir:
public interface Identiable {
public long getId();
public void setId(long id);
}
Se Entity implementar as interfaces Nameable e Identiable, sem o uso de AspectJ,
ser a necess ario estender uma das classes de implementac ao default e implementar a outra
interface, isto pode gerar duplicidade de c odigo. Entretanto, se a mesma abordagem de
comportamento default em AspectJ for utilizada para a interface Identiable, a classe
Entity n ao precisar a implementar os seus m etodos, podendo utilizar as implementac oes
default de ambas interfaces.
public interface Identiable {
public long getId();
public void setId(long id);
static aspect DefaultImplementation {
public long Identiable.id;
public long Identiable.getId() {
return id;
}
public void Identiable.setId(long id) {
this.id = id;
}
}
}
Com isto, a classe Entity implementa ambas as interfaces e o efeito e o mesmo de
estender as duas implementac oes default se heranca m ultipla fosse permitida em Java.
Modicac ao da Hierarquia de Tipos
Em AspectJ, e possvel modicar a hierarquia de classes, de modo a denir su-
perclasses e implementac ao de interfaces para classes e interfaces j a existentes, desde que
isto n ao viole as regras de heranca de Java. Como conseq u encia, obt em-se o desacopla-
mento dos aspectos e das classes especcas da aplicac ao, aumentando, assim, o grau de
re uso dos aspectos.
25
Tais declarac oes t em a forma:
declare parents: tipo-lho implements lista-interfaces;
declare parents: tipo-lho extends classe-ou-lista-interfaces;
Por exemplo, a declarac ao a seguir dene que a classe Temperature implementa a
interface Subject:
declare parents: Temperature implements Subject;
A declarac ao de parents deve obedecer ` as regras de hierarquias de classes em
Java. Por exemplo, n ao e possvel declarar superclasses para interfaces, ou ent ao denir
superclasses que resultem em heranca m ultipla.
Declarac ao de Erros e Advert encias de Compilac ao
Em AspectJ, e possvel declarar erros e advert encias de compilac ao. Com este
mecanismo, obt em-se comportamento similar ao obtido por meio das diretivas de compi-
lac ao #error e #warning.
A construc ao declare error permite denir erros de compilac ao para serem exi-
bidos quando o compilador detectar a presenca de pontos de junc ao identicados por um
dado conjunto de junc ao. O compilador de AspectJ ent ao lanca um erro, imprime a men-
sagem especicada para cada uso indevido e termina o processo de compilac ao. Esta
construc ao tem a forma:
declare error: conjunto-junc ao : mensagem-erro;
Da mesma forma, e possvel denir advert encias de compilac ao, em que uma
mensagem de erro e gerada, mas o processo de compilac ao n ao e interrompido:
declare warning: conjunto-junc ao : mensagem-erro;
O exemplo abaixo permite controlar a operac ao de escrita no campo x da classe
Point, permitindo que somente o m etodo setX lhe faca o acesso direto. Isto obriga todos
os demais m etodos a utilizarem setX, mesmo dentro da classe Point:
declare error: set(int Point.*) && !withincode(void Point.set*(int)):
"Use setter method, even inside Point class.";
Enfraquecimento de Excec oes
A linguagem Java obriga que todas as excec oes, com excec ao das subclasses de
RuntimeException e Error, sejam declaradas na assinatura dos m etodos ou capturadas e
tratadas. Esta abordagem e util por lembrar o desenvolvedor de tratar condic oes de erro
no programa.
Entretanto, emalgumas situac oes, e possvel ter certeza de que uma excec ao nunca
ocorre, de modo que o c odigo necess ario para tratar a excec ao torna-se in util e polui
a implementac ao. Por exemplo, considere que um m etodo escreva informac oes em um
arquivo tempor ario e, logo em seguida, abra este arquivo para leitura. A operac ao de
abertura do arquivo deve estar contida em um trecho de c odigo que trate a excec ao de
arquivo n ao encontrado, FileNotFoundException. Entretanto, o c odigo de tratamento ou
26
de relancamento da excec ao e in util, pois tem-se certeza de que o arquivo existe ele
acabou de ser criado pelo pr oprio programa.
Em AspectJ, e possvel, por meio da construc ao declare soft, silenciar excec oes
de forma seletiva e relanc a-las como excec oes n ao checadas. Esta construc ao e constituda
por uma excec ao e por um conjunto de junc ao. A sua sem antica consiste em enfraquecer
a excec ao para o conjunto de junc ao especicado, fazendo com que o compilador Java
n ao exija o seu tratamento.
declare soft: tipo-excec ao : conjunto-de-junc ao;
No exemplo acima considere que o m etodo void SomeClass.someMethod() crie
um arquivo tempor ario e, em seguida reabra este arquivo para leitura, de modo que n ao h a
d uvidas de que o arquivo exista. A declarac ao a seguir dene que a excec ao n ao precisa
ser tratada, o que simplica a escrita do m etodo:
declare soft: FileNotFoundException
: withincode(void SomeClass.someMethod());
4.3. Conclus ao
A linguagem AspectJ permite a implementac ao de programac ao orientada por aspectos
em Java. Seus mecanismos de transversalidade permitem realizar interfer encias tanto na
estrutura est atica das classes de umprograma Java quanto no comportamento do programa
durante a sua execuc ao.
Dentre as linguagens que implementam orientac ao por aspectos, destacam-se Hy-
perJ [32], Jiazzi [29], AspectC++ [2], DemeterJ [26], AspectWerkz [4].
A linguagem HyperJ [32] foi desenvolvida pela IBM para o suporte ` a metodologia
de separac ao multi-dimensional e integrac ao de requisitos em Java. O objetivo desta me-
todologia e quebrar a tirania da decomposic ao dominante, permitindo que cada requisito
seja implementado em uma dimens ao distinta, de modo que o ambiente de compilac ao
faca a composic ao, de forma semelhante ` a feita em AspectJ.
A linguagem Jiazzi [29] e uma extens ao de Java que permite a compilac ao se-
parada de m odulos denominados units. Estas units funcionam de forma semelhante a
aspectos em AspectJ, podendo alterar a estrutura e o comportamento de classes.
A linguagem AspectC++ [2] e uma implementac ao de orientac ao por aspectos em
C++, com projeto baseado na linguagem AspectJ.
DemeterJ [26] e uma implementac ao da metodologia de programac ao adaptativa
em Java. O seu objetivo e modularizar a implementac ao de requisitos relacionados a
travessia de objetos em um sistema.
AspectWerkz [4] implementa transversalidades est atica e din amica, permitindo
que o processo de costura de c odigo seja feito durante a compilac ao ou durante a execuc ao.
A sua implementac ao e exvel, permitindo que c odigo de transversalidade seja imple-
mentada como combinac ao de c odigo Java com anotac oes e arquivos XML.
O poder de express ao e recursos especiais destas linguagens para desenvolvimento
de sistemas baseados em aspectos situam-se em um mesmo patamar de equival encia.
Entretato, AspectJ destaca-se por sua grande difus ao e alta ader encia ` a proposta inicial do
criador da programac ao orientada por aspectos.
27
5. Exemplos de Aplicac oes de Orientac ao por Aspectos
5.1. Introduc ao
Nesta sec ao, s ao discutidas implementac oes de bibliotecas reutiliz aveis utilizando orien-
tac ao por aspectos. Na primeira parte, e mostrada a implementac ao de um mecanismo
modular e n ao-intrusivo para a gerac ao de registros de operac oes. Em seguida, mostra-se
uma implementac ao em AspectJ do padr ao singleton [15], em que o c odigo de controle
do padr ao e separado do c odigo da classe implementada para se ter inst ancia unica. O
terceiro exemplo da sec ao e a implementac ao em AspectJ de outro importante padr ao de
projetos, o observador [15]; esta implementac ao e tamb em n ao-intrusiva e n ao exige que
as classes participantes implementem as interfaces pr e-denidas para o padr ao.
5.2. Gerac ao de Registros de Operac oes
Apresenta-se, nesta sec ao a implementac ao completa das classes e aspectos para gerac ao
de registros de operac oes. A implementac ao por meio de aspectos desta funcionalidade
foi adaptada da soluc ao apresentada em [16].
A classe respons avel pela gerac ao dos registros de operac oes e a classe Logger,
denida a seguir. Esta classe possui m etodos para registrar entradas de m etodos, sadas
de m etodos por meio de retorno ou por meio de lancamento de excec oes e registro de
tratamento de excec oes.
public class Logger {
public static void logEntry(String signature) {
System.out.println("Entering " + signature);
}
public static void logNormalExit(String signature) {
System.out.println("Normal return of " + signature);
}
public static void logExitWithException(String signature, Exception exc) {
System.out.println("Return of " + signature + " with exception " + exc);
}
public static void logExceptionHandling(Exception exc) {
System.out.println("Handling exception " + exc);
}
}
Observando-se os m etodos que cont em chamadas dos m etodos da classe Logger,
observa-se quais pontos do programa s ao os candidatos a pontos de junc ao. Pelo exemplo
da Sec ao 2, v e-se que h a c odigo de gerac ao de registros espalhados no incio e no nal
dos corpos de cada m etodo. Esta constatac ao leva ` a denic ao do conjunto de junc ao
loggableCalls. Al em disso, e preciso registrar tamb em as execuc oes dos tratadores de
excec oes, sendo assim necess ario denir o conjunto de junc ao exceptionHandling.
28
Considere o aspecto denido a seguir:
public aspect LoggingAspect {
pointcut publicMethods(): execution(public * *(..));
pointcut logObjectCalls() : execution(* Logger.*(..));
pointcut loggableCalls() : publicMethods() && ! logObjectCalls();
pointcut exceptionHandling(Exception exc): handler(Exception+) && args(exc);
before(): loggableCalls() {
Logger.logEntry(thisJoinPoint.getSignature().toString());
}
after() returning: loggableCalls() {
Logger.logNormalExit(thisJoinPoint.getSignature().toString());
}
after() throwing (Exception exc) : loggableCalls() {
Logger.logExitWithException(thisJoinPoint.getSignature().toString(), exc);
}
before(Exception exc): exceptionHandling(exc) {
Logger.logExceptionHandling(exc);
}
}
O aspecto LoggingAspect dene os conjuntos de junc ao para captura dos m etodos
cujas execuc oes devem ser registradas (loggableCalls) e para captura de tratamento de
excec oes (exceptionHandling). O conjunto de junc ao exceptionHandling e parametrizado
para permitir a impress ao do nome da excec ao na gerac ao do registro de operac oes.
As regras de junc ao do aspecto chamam os m etodos da classe Logger com os
par ametros apropriados para fazer os registros da execuc ao. A regra before no conjunto
de junc ao loggableCalls indica que a chamada de Logger.logEntry deve ser includa antes
da execuc ao de todos os m etodos p ublicos do programa. Da mesma forma, as regras after
para o mesmo conjunto de junc ao denem os m etodos a serem chamados ao nal de cada
execuc ao de m etodo. O uso de returning e throwing permite que o retorno normal e o
retorno com lancamento de excec ao sejam tratados diferentemente.
Como aspecto LoggingAspect e possvel modularizar toda a poltica de gerac ao de
registros de operac ao do programa. No momento do weaving, as chamadas dos m etodos
da classe Logger s ao adicionadas nos pontos de junc ao identicados por loggableCalls, de
modo que o comportamento do programa e id entico ao obtido no exemplo da Sec ao 2.3.
5.3. Padr ao Singleton
O padr ao singleton tem por objetivo denir classes das quais se pode ter apenas uma
inst ancia. Exemplos de uso do padr ao singleton s ao f abricas de sess oes, que possuem,
geralmente, uma unica inst ancia no programa. Em geral, as subclasses podem criar
inst ancias da classe singleton.
Nesta sec ao apresentam-se o padr ao singleton [15] e as diculdades em denir
este padr ao em linguagens orientadas por objetos, em especial quando as classes parti-
cipantes n ao implementam as interfaces pr e-denidas para o padr ao. Mostra-se a partir
da como a denic ao de um pequeno conjunto de aspectos permite tornar qualquer classe
29
participante do padr ao, independentemente do seu intuito inicial. A implementac ao por
meio de aspectos para este padr ao foi adaptada da soluc ao apresentada em [19].
O exemplo ilustrado nesta sec ao e uma implementac ao do padr ao singleton para
uma classe Printer. Para garantir inst ancia unica deve-se denir o construtor da classe
como privado ou protegido. O uso de protegido garante, ainda, que as subclasses podem
criar inst ancias da superclasse. Os objetos do programa que desejarem obter a inst ancia
unica da classe devem utilizar o m etodo est atico instance, que retorna a inst ancia unica
caso exista, ou cria uma nova inst ancia se ainda nenhuma tiver sido criada. Utiliza-se um
atributo est atico, uniqueInstance para armazenar a inst ancia unica da classe.
// Implements a Printer as a singleton
public class PrinterSingleton {
private static int objectsSoFar = 0; // Counts the instances of this class
private static PrinterSingleton uniqueInstance = null; // Stores the printer unique instance
private int id; // Each instance has a distinct id
protected PrinterSingleton() { // Creates a new printer: note it is protected
id = ++objectsSoFar;
}
public static PrinterSingleton instance() { // Factory method used to create a new instance
if (uniqueInstance == null) {
uniqueInstance = new PrinterSingleton();
}
return uniqueInstance;
}
public void print() { // Prints the instance of the printer
System.out.println("\tMy ID is " + id);
}
}
Os seguintes problemas de modularizac ao podem ser vistos neste c odigo: (i) o
c odigo de denic ao do padr ao e intrusivo no c odigo da classe; (ii) o c odigo de denic ao
do padr ao n ao pode ser reaproveitado em outras classes que precisarem fazer controle de
unica inst ancia; (iii) e possvel violar o protocolo singleton dentro de pacotes ou subclas-
ses em Java. Para evitar estes problemas, pode-se criar o aspecto abstrato SingletonProto-
col, denido a seguir.
import java.util.Hashtable;
// Denes the general behavior of the Singleton design pattern.
public abstract aspect SingletonProtocol {
private Hashtable singletons = new Hashtable(); // Stores the singletons instances
public interface Singleton {} // Denes Singleton interface, implemented by singleton classes
public pointcut protectionExclusions(); // Denes which points are allowed to create new instances
// Protects the constructor of a singleton class
Object around() : call((Singleton +).new (..)) && !protectionExclusions() {
Class singleton = thisJoinPoint.getSignature().getDeclaringType();
if (singletons.get(singleton) == null)
singletons.put(singleton, proceed());
return singletons.get(singleton);
}
}
30
Este aspecto usa uma tabela, singletons, para conter as inst ancias unicas de cada
classe, e dene uma interface Singleton, que e utilizada nos subaspectos de Singleton-
Protocol para garantir consist encia de tipos com a implementac ao. O conjunto de junc ao
protectionExclusions pode ser utilizado para denir pontos que t em a permiss ao de criar
inst ancias de uma classe singleton; por exemplo, subclasses de uma classe singleton po-
dem criar novas inst ancias da classe.
A garantia de unicidade de inst ancia de uma classe e feita pela regra around, que e
executada ao redor das chamadas de construtor das classes que implementam a interface
Singleton. Oc odigo da regra tenta localizar na tabela singletons a inst ancia unica da classe
cujo construtor est a sendo chamado. Se nenhuma inst ancia da classe for encontrada na
tabela, ent ao armazena-se uma nova inst ancia criada por meio da chamada de proceed().
A inst ancia na tabela e ent ao retornada como resultado da chamada do construtor.
A seguir, apresentam-se a classe Printer, que n ao possui c odigo de implementac ao
do padr ao, e uma subclasse PrinterSubclass, que n ao implementa o padr ao singleton.
public class Printer {
private static int objectsSoFar = 0; // Counts the instances of the class
private int id; // Each instance has a distinct id
public Printer() { // Constructor: note it is not protected
id = ++objectsSoFar;
}
public void print() { // Prints the id of the instance
System.out.println("\tMy ID is " + id);
}
}
// This class has access to the singleton constructor
public class PrinterSubclass extends Printer {
public PrinterSubclass() { // Creates an instance of this class
super();
}
}
Para garantir a exist encia de uma unica inst ancia da classe Printer, dene-se o as-
pecto SingletonInstance, que estende SingletonProtocol. Dene-se neste aspecto que a
classe Printer implementa a interface Singleton. Al em disso, redene-se o conjunto de
junc ao protectionExclusions, que captura todas as chamadas de construtor de PrinterSub-
class; isto permite que esta classe e suas subclasses possam instanciar Printer.
// Implements a concrete instance of the Singleton pattern. It declares
// Printer to be Singleton and denes an exception to the constructor
// protection: PrinterSubclass (a subclass of the Singleton) can still
// access Printers constructor.
public aspect SingletonInstance extends SingletonProtocol {
// Gives Printer the Singletons protection
declare parents : Printer implements Singleton;
// Allows Printer subclasses to access the constructor
public pointcut protectionExclusions(): call((PrinterSubclass +).new (..));
}
31
A implementac ao do padr ao singleton via aspectos e n ao-intrusiva, pois n ao e ne-
cess ario alterar a interface da classe para que esta seja adequada ao padr ao. Al em disso, o
c odigo do padr ao pode ser completamente reaproveitado em outras implementac oes; com
efeito, para denir que outra classe qualquer possui inst ancia unica, basta acrescentar ou-
tra declarac ao de implementac ao da interface Singleton no aspecto SingletonInstance. Por
meio da redenic ao do conjunto de junc ao protectionExclusion, e possvel ainda permitir
que subclasses possuam m ultiplas inst ancias, sem a necessidade de denir o construtor da
classe de unica inst ancia como protegido (protected). Desta maneira, n ao e necess ario vi-
olar o princpio aberto-fechado
2
[28, 30] para permitir m ultiplas inst ancias das subclasses
de uma classe de unica inst ancia.
5.4. Padr ao Observador
A implementac ao do padr ao observador por meio de linguagens orientadas por objetos
puras, como a mostrada na Sec ao 2.4, apresenta problemas de modularizac ao, devido a
c odigo de atualizac ao dos observadores estar espalhado ao longo do c odigo dos objetos
observados. Nesta sec ao, apresenta-se uma implementac ao do padr ao observador utili-
zando AspectJ. A implementac ao por meio de aspectos para este padr ao foi adaptada da
soluc ao apresentada em [19].
O aspecto abstrato ObserverProtocol, denido a seguir, e respons avel por mapear
objetos em seus observadores. Este aspecto possui os seguintes elementos:
as interfaces Subject e Observer representam, respectivamente, um objeto alvo
de observac ao, doravante denominado alvo, e um observador; estas interfaces s ao
utilizadas para consist encias de tipos nos demais elementos do aspecto;
o mapeamento perSubjectObservers e respons avel por armazenar as listas de ob-
servadores de cada alvo;
os m etodos addObserver e removeObserver s ao respons aveis por adicionar e re-
mover um observador da lista de observadores de um alvo, respectivamente;
o m etodo getObserver e respons avel por retornar a lista de observadores de um
alvo, armazenada na tabela perSubjectObservers; e respons avel tamb em por criar
uma nova lista vazia e associ a-la a um alvo, caso este ainda n ao esteja cadastrado
na tabela;
o conjunto de junc ao abstrato subjectChange deve ser redenido nos subaspec-
tos de ObserverProtocol; nos subaspectos, ele dene os m etodos respons aveis por
alterar o estado interno dos objetos observados (ver aspecto TemperatureObser-
vation, denido a seguir);
o m etodo abstrato updateObserver deve ser redenido nos subaspectos, de modo
que dena as ac oes de noticac ao dos observadores quando o estado interno do
sujeito for alterado;
a regra after denida para o conjunto de junc ao subjectChange e respons avel por
obter a lista de observadores de um alvo e chamar o m etodo de noticac ao para
cada observador; este c odigo e includo ap os cada ponto de junc ao que represente
uma mudanca de estado do objeto alvo.
A implementac ao do aspecto e a seguinte:
2
A classe de unica inst ancia e aberta para extens oes, mas fechada para modicac oes.
32
import java.util.List;
import java.util.LinkedList;
import java.util.Iterator;
import java.util.WeakHashMap;
public abstract aspect ObserverProtocol {
public interface Subject {}
public interface Observer {}
private WeakHashMap perSubjectObservers;
private List getObservers(Subject s) {
if (perSubjectObservers == null) {
perSubjectObservers = new WeakHashMap();
}
List observers = (List) perSubjectObservers.get(s);
if (observers == null) {
observers = new LinkedList();
perSubjectObservers.put(s, observers);
}
return observers;
}
public void addObserver(Subject s, Observer o) {
getObservers(s).add(o);
updateObserver(s,o);
}
public void removeObserver(Subject s, Observer o) {
getObservers(s).remove(o);
}
abstract public pointcut subjectChange(Subject s);
abstract public void updateObserver(Subject s, Observer o);
after(Subject s): subjectChange(s) {
Iterator it = getObservers(s).iterator();
while (it.hasNext()) {
updateObserver(s, (Observer) it.next());
}
}
}
Para implementar o padr ao observador utilizando aspectos, deve-se denir: (i) os
objetos alvo de observac ao; (ii) os objetos observadores; (iii) as operac oes dos alvos que
denem as alterac oes do estado interno; (iv) o algoritmo de atualizac ao de cada observa-
dor; (v) os momentos em que a observac ao sobre um alvo inicia e termina.
Para denir que uma classe e observadora de outra, deve-se implementar um as-
pecto que estenda ObserverProtocol e que dena o conjunto de junc ao de modicac ao do
estado interno e o m etodo de noticac ao de observadores.
33
Considere, por exemplo, as classes Termometer e Temperature a seguir:
public abstract class Termometer {
public abstract void printTemperature(double value);
}
public class Temperature {
private double value;
public Temperature(double initialValue) {
value = initialValue;
}
public double getValue() {
return value;
}
public void setValue(double value) {
this.value = value;
}
}
O aspecto TemperatureObservation, mostrado a seguir, estende o aspecto Obser-
verProtocol, denindo que Termometer implementa a interface Observer, Temperature
implementa a interface Subject. Denem-se tamb em que o conjunto de junc ao sub-
jectChange representa todas as execuc oes do m etodo Temperature.setValue, e que a
noticac ao dos observadores e feita por meio da chamada do m etodo de impress ao da
temperatura, Termometer.printTemperature.
public aspect TemperatureObservation extends ObserverProtocol {
declare parents: Temperature implements Subject;
declare parents: Termometer implements Observer;
public pointcut subjectChange(Subject s)
: target(s) && execution(void Temperature.setValue(double));
public void updateObserver(Subject s, Observer o) {
Temperature temperature = (Temperature) s;
Termometer termometer = (Termometer) o;
termometer.printTemperature(temperature.getValue());
}
}
A seguir, denem-se duas subclasses Termometer: TermometerCelsius e Termo-
meterFahrenheit.
public class TermometerCelsius extends Termometer {
public void printTemperature(double value) {
System.out.println("Celsius: " + value);
}
}
34
<<stereotype>>
&DOOHU
<<stereotype>>
2SHUDWLRQ
+operation( ... )
+context: CallerContext
+doSomething( )
suboperations
<<stereotype>>
:RUNHU
+work( ... )
Figura 7: Representac ao em UML do padr ao wormhole.
public class TermometerFahrenheit extends Termometer {
public void printTemperature(double value) {
System.out.println("Fahrenheit: " + value);
}
}
Para associar uma inst ancia de uma classe term ometro como observadora de uma
inst ancia de temperatura, utiliza-se o m etodo addObserver do aspecto, como mostrado a
seguir:
TermometerCelsius term1 = new TermometerCelsius();
TermometerFahrenheit term2 = new TermometerFahrenheit();
TemperatureObservation.aspectOf().addObserver(t,term1);
TemperatureObservation.aspectOf().addObserver(t,term2);
O m etodo aspectOf e utilizado para referenciar a inst ancia unica de um aspecto.
As principais vantagens da abordagem s ao:
a modularizac ao completa do padr ao: foram retirados das classes do objeto ob-
servado e do observador os c odigos necess arios para implementac ao do padr ao
observador;
aumento do grau de re uso do padr ao: pode-se denir de maneira n ao-intrusiva
qualquer classe como observador ou alvo de observac ao, denindo-se somente
um aspecto que implemente o respectivo protocolo de observac ao.
5.5. Padr ao Wormhole
Considere o conjunto de classes denido na Figura 7, em que uma chamada tpica de
operac ao gera a execuc ao de diversas operac oes secund arias, representadas na forma do
grafo da Figura 8. A implementac ao por meio de aspectos para este padr ao foi adaptada
da soluc ao apresentada em [16].
Se um objeto Worker precisar de informac oes a respeito do contexto do objeto
Caller que iniciou a execuc ao das operac oes, pode-se denir par ametros nas chamadas de
m etodos dos objetos Operation para que este contexto seja propagado at e os objetos Wor-
ker. Esta implementac ao gera intrus ao, pois os objetos Operation podem n ao necessitar
35
Caller Operation
Worker Worker Worker
op op
op op
op op
<<context>>
<<context>> <<context>>
<<context>> <<context>>
<<context>>
<<context>>
<<context>>
<<context>> <<context>> <<context>>
Figura 8: Implementac ao de transmiss ao de contexto via passagem de
par ametros (Extrada de [20])
Caller Operation
Worker Worker Worker
op op
op op
op op
<<context>>
<<context>> <<context>> <<context>>
Figura 9: Representac ao gr aca do padr ao wormhole (Extrada de [20]).
36
das informac oes de contexto. Neste caso, a exist encia destes par ametros pode tornar com-
plexas as interfaces das classes Operation, produzindo assim alto grau de acoplamento
entre m odulos. Outra soluc ao possvel e denir uma area de acesso global, onde o objeto
Caller armazena seus dados para leitura pelos objetos Worker. Esta situac ao tamb em gera
alto grau de acoplamento entre os objetos Caller e Worker.
O padr ao wormhole tem por objetivo denir um canal direto de comunicac ao entre
os objetos Caller e Worker, tornando disponvel para os objetos Worker as informac oes
de contexto que ele precisar. Este padr ao permite encapsular a comunicac ao entre estes
objetos, propiciando uma implementac ao com grau de acoplamento menor que as im-
plementac oes que passam o contexto como par ametro ou o armazenam em uma area de
acesso global.
Figura 9 esquematiza a implementac ao da passagem de contexto por meio do
padr ao wormhole. Nesta implementac ao, a informac ao de contexto e transmitida dire-
tamente do objeto Caller para os objetos Worker, sem a necessidade de alterar a interface
dos objetos Operation.
O aspecto WormholePattern dene o padr ao wormhole.
public aspect WormholePattern {
pointcut invocations(Caller c):
this(c) && call(void Operation.doOperation());
pointcut workPoints(Worker w):
target(w) && call(void Worker.doWork());
pointcut perCallerWork(Caller c, Worker w):
cow(invocations(c)) && workPoints(w);
before (Caller c, Worker w): perCallerWork(c, w) {
w.setCallerContext(c.getContext());
}
}
Neste aspecto, denem-se os seguintes conjuntos de junc ao:
invocations: pontos de chamadas de m etodos da classe Operation, ou suas sub-
classes, que ocorrerem em m etodos cujo objeto receptor e da classe Caller;
workPoints: pontos de chamadas do m etodo doWork da classe Worker;
perCallerWork: pontos de chamadas do m etodo Worker.doWork() ou suas subclas-
ses, que ocorrerem no uxo de execuc ao de uma invocac ao de operac ao a partir
de m etodos da classe Caller.
A regra before aplicada ao conjunto de junc ao perCallerWork propaga para o
objeto Worker o contexto do objeto Caller cujo uxo de execuc ao gerou a chamada ao
m etodo Worker.doWork().
A implementac ao por meio de aspectos permite obter a propagac ao direta de
informac oes de contexto, sem aumentar a interface da classe Operation ou aumentar o
acoplamento entre as classes Caller e Worker por meio de valores globais. Al em disso,
todo o acoplamento entre as classes Caller e Worker e controlado pelo aspecto Wormhole-
Pattern, que funciona como mediador. Quaisquer alterac oes no contexto geram alterac oes
somente neste aspecto, de modo que as classes participantes n ao precisam ser alteradas.
37