Feature Oriented Programming (FOP)
FOP estende o design
orientado a objetos por meio de mecanismos de modularização e composição de features. De acordo com a documentação apresentada na suite de ferramentas
AHEAD, uma implementação de FOP, features correspondem às unidades incrementais do programa e que encapsulam fragmentos espalhados por diferentes classes. O mecanismo de composição de FOP, em certo grau, é semelhante ao de Mixins.
Implementação de Variações usando AHEAD
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)
Um modelo AHEAD consiste em um diretório raiz. Nesse caso, criamos um diretório "EPL". O mecanismo de composição de AHEAD consiste em adicionar incrementos (features) a uma versão base da aplicação. Tanto a aplicação base quanto as features são definidas em sub-diretórios. Para esse exemplo, criamos a seguinte estrutura de diretórios:
EPL
+ Base
+ Int
+ Double
+ Extended
+ Print
Versão Base
No diretório base, são criados os artefatos comuns a linha de produtos. Note que artefatos AHEAD possuem a extensão ".jak". Para a definição base do produto, os artefatos são classes e interfaces java.
Base/Expression.jak
public interface Expression {
public Value eval();
}
Base/Value.jak
public class Value implements Expression {
public Value eval() {
return this;
}
}
Base/BinaryExpression.jak
public abstract class BinaryExp implements Expression {
protected Expression left;
protected Expression right;
protected String operator;
public BinaryExp(Expression left, Expression right, String operator) {
this.left = left;
this.right = right;
this.operator = operator;
}
public Expression getLeft() {
return left;
}
public Expression getRight() {
return right;
}
public String getOperator() {
return operator;
}
}
Base/AddExpression.jak
public class AddExp extends BinaryExp {
public AddExp(Expression left, Expression right) {
super(left, right, "+");
}
public Value eval() {
return new Value(left.eval().getValue() + right.eval().getValue());
}
}
Base/SubExpression.jak
public class SubExp extends BinaryExp {
public SubExp(Expression left, Expression right) {
super(left, right, "-");
}
public Value eval() {
return new Value(left.eval().getValue() - right.eval().getValue());
}
}
Features Int e Double
As features
Int e
Double basicamente refinam a classe Value, configurando corretamente o tipo da propriedade
value. Noque que, nesses casos, não definimos novas classes ou interfaces. Os incrementos, ou features, são implementados com "refinamentos" das classes e/ou das interfaces existentes.
Int/Value.jak
refines class Value {
protected int value;
public Value(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
}
Double/Value.jak
refines class Value {
protected double value;
public Value(double value) {
this.value = value;
}
public double getValue() {
return this.value;
}
}
Feature Extended (suporte a multiplicação e divisão)
A definição da feature Extended segue um princípio semelhante, por outro lado, apenas definimos classes para suportar as expressões de multiplicação e divisão.
Extended/MultExp.jak
public class MultExp extends BinaryExp {
public MultExp(Expression left, Expression right) {
super(left, right, "*");
}
public Value eval() {
return new Value(left.eval().getValue() * right.eval().getValue());
}
}
Extended/DivisionExp.jak
public class DivisionExp extends BinaryExp {
public DivisionExp(Expression left, Expression right) {
super(left, right, "/");
}
public Value eval() {
return new Value(left.eval().getValue() / right.eval().getValue());
}
}
Feature Print
Finalmente, definimos a feature Print refinando a inteface Expression e as classe Value e BinaryExpression.
Print/Expression.jak
refines interface Expression {
public String print();
}
Print/Value.jak
refines class Value {
public String print() {
return "" + value;
}
}
Print/BinaryExp.jak
refines class BinaryExp {
public String print() {
return left.print() + operator + right.print();
}
}
Processo de Composição
AHEAD diponibiliza um conjunto de ferramentas para fazer a composição de programas. A documentação é bem detalhada, e o processo de configuração não chega a ser traumático (mesmo no Windows, que requer a ferramenta Cygwin). Importante destacar que a versão mais nova também requer Java 1.6 em diante.
Por exemplo, para fazer a geração de um avaliador de expressões com a configuração (Base + Int + Print), executamos a seguinte seqüencia de comandos:
EPL $ composer --target=out Base Int Print
EPL $ cd out
EPL / out $ jak2java *.jak
Pronto, com isso geramos um conjunto de classes chave que corresponde a definição do produto (Base + Int + Print). Se desejarmos o produto (Base + Double + Extended + Print), basta alterar a chamada do composer para: *composer --target=out Base Double Extended Print.
Existem outros recursos da suite AHEAD que não foram cobertos nesse exemplo.
--
RodrigoBonifacio - 29 Aug 2008