AspectJ
Tecnologia orientada a aspectos desenvolvida como uma extensão da linguagem de programação Java.
Implementação de Variações em AspectJ
Esse exemplo consiste em adaptar o avaliador de expressões de acordo com:
- 1 - o tipo da expressão (int ou double).
- 2 - suporte opcional a geração de uma representação String das expressões.
- 3 - suporte alternativo a expressões básicas (soma e subtração) ou avançadas (que inclui divisão e multiplicação)
Em linhas gerais, o que será feito é a implentação destas variações a partir de um código base. Os arquivos deste exemplo estão disponíveis para download aqui:
epl_base.rar e
epl_aspectJ.rar
Variação 1
-> Estratégia utilizada: deixar o código da base apenas com o tipo Inteiro e implementar o tipo Double em aspectos (construtores de AspectJ utilizados: pointcuts e advices)
Passo 1 - efetuar refactoring no código das expressões para deixá-lo somente com o tipo inteito
Exemplo: AddExp.java
public class AddExp extends BinaryExp {
...
public Value evaluate() {
Value leftValue = getLeft().evaluate();
Value rightValue = getRight().evaluate();
if (leftValue instanceof DoubleValue)
return new DoubleValue(((DoubleValue) leftValue).value()
+ ((DoubleValue) rightValue).value());
else
return new IntegerValue(((IntegerValue) leftValue).value()
+ ((IntegerValue) rightValue).value());
}
}
AddExp.java depois do refactoring
public class AddExp extends BinaryExp {
...
public Value evaluate() {
return new IntegerValue(((IntegerValue) getLeft().evaluate()).value()
+ ((IntegerValue) getRight().evaluate()).value());
}
}
Passo 2 -> Criar aspectos para implentação do tipo Double:
public abstract aspect DoubleTypeAspect {
pointcut callEval() : call (public Value Expression.evaluate(..));
pointcut addValue(Parser p, String value): call (public void Parser.addValue(..))
&& args(value) && target(p);
void around(Parser p, String value): addValue(p,value) {
p.getExp().add(new DoubleValue(Double.parseDouble(value)));
}
}
public aspect AddSubDoubleTypeAspect extends DoubleTypeAspect{
pointcut add(Expression e) : if(e instanceof AddExp) && target(e);
...
Value around(Expression e) : callEval()&& add(e){
AddExp ae = (AddExp)e;
return new DoubleValue(
((DoubleValue)ae.getLeft().evaluate()).value() + (DoubleValue)ae.getRight().evaluate()).value() );
}
...
}
-> Para gerar produtos da linha com o tipo Double, basta incluir na build do sistema os aspectos
DoubleTypeAspect.aj e
AddSubDoubleTypeAspect.aj. Caso a opção de multiplicação e divisão também fizer parte de um determinado produto, incluir também o aspecto
MulDivDoubleTypeAspect.aj.
Variação 2
Estratégia utilizada: introduzir a operação Print nas classes necessárias através de aspectos. (construtores de AspectJ utilizados: inter-types, pointcuts e advices)
public privileged aspect PrintAspect {
1 public void Expression.print(){}
2 public void Value.print(){
System.out.print(value);
}
3 public void BinaryExp.print(){
left.print();
System.out.print(" "+operator+" ");
right.print();
}
4 pointcut programExecution(Program p) : call(public Value Program.execute(..)) && target(p);
5 before(Program p) : programExecution(p) {
p.getExpression().print();
System.out.print(" = ");
}
1,2,3 - Introduz o método print() na interface Expression.java e classes Value.java e BinaryExpression.java através de inter-type declaration.
4 – Captura chamadas da execução do método execute da classe Program
5 – Antes da execução de joinpoints capturados pelo pointcut definido em 4, inclui-se a chamada ao método print() da expressão que está sendo avaliada.
-> Para gerar produtos da linha com a operação Print presente, basta incluir o aspecto PrintAspect.aj na build do sistema.
Variação 3
A inclusão das operações de multiplicação e divisão em um produto não foram implentadas com aspectos. A técnica de OO, polimorfismo de subtipos (herança simples), resolve melhor este tipo de variação. Para gerar um produto da linha com suporte a estas operações, inclui-se na build do sistema as classes correspondentes.
--
FernandaDamorim - 28 Aug 2008