Carregar apresentação
A apresentação está carregando. Por favor, espere
1
Programação orientada a aspectos com C#
Paulo Borba e André Furtado Centro de Informática Universidade Federal de Pernambuco
2
Programação orientada a aspectos é...
uma nova técnica de programação que oferece suporte à modularização de crosscutting concerns
3
Ou seja, programação orientada a aspectos é...
uma nova técnica de programação que oferece suporte à modularização de “requisitos” que afetam várias partes de uma aplicação
4
Persistência é um crosscutting concern
public class Banco { private CadastroContas contas; private Banco() { contas = new CadastroConta (new RepositorioContasAccess()); } public void Cadastrar(Conta conta) { Persistence.DBHandler.StartTransaction(); try { contas.Cadastrar(conta); Persistence.DBHandler.CommitTransaction(); } catch (System.Exception ex){ Persistence.DBHandler.RollBackTransaction(); throw ex; public void Transferir(string numeroDe, string n umeroPara, double valor) { contas.Transferir(numeroDe, numeroPara, valor); public class CadastroContas { private RepositorioContas contas; public void Debitar(string numero, double valor) { Conta c = contas.Procurar(numero); c.Debitar(valor); contas.Atualizar(c); } public void Transferir(string numeroDe, string n umeroPara, double valor) { Conta de = contas.Procurar(numeroDe); Conta para = contas.Procurar(numeroPara); de.Debitar(valor); para.Creditar(valor); contas.Atualizar(de); contas.Atualizar(para); public double Saldo(string numero) { return c.Saldo; public class RepositorioContasAccess : RepositorioContas { public void Inserir(Conta conta) { string sql = "INSERT INTO Conta (NUMERO,SALDO) VALUES ('" + conta.Numero + "'," + conta.Saldo + ")"; OleDbCommand insertCommand = new OleDbCommand (sql,DBHandler.Connection,DBHandler.Transaction); insertCommand.ExecuteNonQuery(); } public void Atualizar(Conta conta) { string sql = "UPDATE Conta SET SALDO = (" + conta.As ldo + ") WHERE NUMERO = '" + conta.Numero + "'"; OleDbCommand updateCommand = new OleDbCommand(s ql,DBHandler.Connection,DBHandler.Transaction); int linhasAfetadas; linhasAfetadas = updateCommand.ExecuteNonQuery(); if (linhasAfetadas == 0) { throw new ContaNaoEncontradaException(conta.Numero); public class Conta { private string numero; private double saldo; public void Creditar(double valor) { this.saldo = this.saldo + valor; } public void Debitar(double valor) { if (valor > saldo) { throw new SaldoInsuficienteException)); else { this.saldo = this.saldo - valor; public void Atualizar(Conta c) { this.numero = c.numero; this.saldo = c.saldo; public class DBHandler { private static OleDbConnection connection; public static OleDbConnection Connection { get { if (connection == null) { string dataSource = "BancoCS.mdb"; string strConexao = "Provider= Microsoft.Jet.OLEDB.4.0; " + "Data Source=" + dataSource; connection = new OleDbConnection(strConexao); } return connection; public static OleDbConnection GetOpenConnection() { Connection.Open(); return Connection; public static void StartTransaction() { transaction = Connection.BeginTransaction(); Código de persistência em vermelho…
5
Crosscutting concerns…
Afetam várias partes da aplicação São relativos à decomposição dominante via classes no caso de OO via funcões no caso das linguagens funcionais
6
Exemplos de crosscutting concerns
Distribuição Controle de concorrência Tratamento de exceções Logging Debugging Variações em linhas de produtos de software Suporte a eventos
7
Há várias técnicas para modularizacao
Procedimentos Classes, herança e subtipos Padrões (arquitetura em camadas) Aspectos Foco em modularizar crosscutting concerns
8
As técnicas de modularização...
São complementares e ajudam a... Separar preocupações (separation of concerns) Aumentar extensibilidade Facilitar reuso Tudo isso vale para aspectos (crosscutting concerns)
9
Sem aspectos public class Banco { private CadastroContas contas;
private Banco() { contas = new CadastroConta (new RepositorioContasAccess()); } public void Cadastrar(Conta conta) { Persistence.DBHandler.StartTransaction(); try { contas.Cadastrar(conta); Persistence.DBHandler.CommitTransaction(); } catch (System.Exception ex){ Persistence.DBHandler.RollBackTransaction(); throw ex; public void Transferir(string numeroDe, string n umeroPara, double valor) { contas.Transferir(numeroDe, numeroPara, valor); public class CadastroContas { private RepositorioContas contas; public void Debitar(string numero, double valor) { Conta c = contas.Procurar(numero); c.Debitar(valor); contas.Atualizar(c); } public void Transferir(string numeroDe, string n umeroPara, double valor) { Conta de = contas.Procurar(numeroDe); Conta para = contas.Procurar(numeroPara); de.Debitar(valor); para.Creditar(valor); contas.Atualizar(de); contas.Atualizar(para); public double Saldo(string numero) { return c.Saldo; public class RepositorioContasAccess : RepositorioContas { public void Inserir(Conta conta) { string sql = "INSERT INTO Conta (NUMERO,SALDO) VALUES ('" + conta.Numero + "'," + conta.Saldo + ")"; OleDbCommand insertCommand = new OleDbCommand (sql,DBHandler.Connection,DBHandler.Transaction); insertCommand.ExecuteNonQuery(); } public void Atualizar(Conta conta) { string sql = "UPDATE Conta SET SALDO = (" + conta.As ldo + ") WHERE NUMERO = '" + conta.Numero + "'"; OleDbCommand updateCommand = new OleDbCommand(s ql,DBHandler.Connection,DBHandler.Transaction); int linhasAfetadas; linhasAfetadas = updateCommand.ExecuteNonQuery(); if (linhasAfetadas == 0) { throw new ContaNaoEncontradaException(conta.Numero); public class Conta { private string numero; private double saldo; public void Creditar(double valor) { this.saldo = this.saldo + valor; } public void Debitar(double valor) { if (valor > saldo) { throw new SaldoInsuficienteException)); else { this.saldo = this.saldo - valor; public void Atualizar(Conta c) { this.numero = c.numero; this.saldo = c.saldo; public class DBHandler { private static OleDbConnection connection; public static OleDbConnection Connection { get { if (connection == null) { string dataSource = "BancoCS.mdb"; string strConexao = "Provider= Microsoft.Jet.OLEDB.4.0; " + "Data Source=" + dataSource; connection = new OleDbConnection(strConexao); } return connection; public static OleDbConnection GetOpenConnection() { Connection.Open(); return Connection; public static void StartTransaction() { transaction = Connection.BeginTransaction();
10
Com aspectos Código base do sistema Código do aspecto de persistência
public class Banco { private CadastroContas contas; private Banco() { contas = new CadastroConta } public void Cadastrar(Conta conta) { contas.Cadastrar(conta); public void Transferir(string numeroDe, string n umeroPara, double valor) { contas.Transferir(numeroDe, numeroPara, valor); public class CadastroContas { private RepositorioContas contas; public void Debitar(string numero, double valor) { Conta c = contas.Procurar(numero); c.Debitar(valor); } public void Transferir(string numeroDe, string n umeroPara, double valor) { Conta de = contas.Procurar(numeroDe); Conta para = contas.Procurar(numeroPara); de.Debitar(valor); para.Creditar(valor); public double Saldo(string numero) { return c.Saldo; public class Conta { private string numero; private double saldo; public void Creditar(double valor) { this.saldo = this.saldo + valor; } public void Debitar(double valor) { if (valor > saldo) { throw new SaldoInsuficienteException)); else { this.saldo = this.saldo - valor; public void Atualizar(Conta c) { this.numero = c.numero; this.saldo = c.saldo; Código base do sistema public class RepositorioContasAccess : RepositorioContas { public void Inserir(Conta conta) { string sql = "INSERT INTO Conta (NUMERO,SALDO) VALUES ('" + conta.Numero + "'," + conta.Saldo + ")"; OleDbCommand insertCommand = new OleDbCommand (sql,DBHandler.Connection,DBHandler.Transaction); insertCommand.ExecuteNonQuery(); } public void Atualizar(Conta conta) { string sql = "UPDATE Conta SET SALDO = (" + conta.As ldo + ") WHERE NUMERO = '" + conta.Numero + "'"; OleDbCommand updateCommand = new OleDbCommand(s ql,DBHandler.Connection,DBHandler.Transaction); int linhasAfetadas; linhasAfetadas = updateCommand.ExecuteNonQuery(); if (linhasAfetadas == 0) { throw new ContaNaoEncontradaException(conta.Numero); public class DBHandler { private static OleDbConnection connection; public static OleDbConnection Connection { get { if (connection == null) { string dataSource = "BancoCS.mdb"; string strConexao = "Provider= Microsoft.Jet.OLEDB.4.0; " + "Data Source=" + dataSource; connection = new OleDbConnection(strConexao); } return connection; public static OleDbConnection GetOpenConnection() { Connection.Open(); return Connection; public static void StartTransaction() { transaction = Connection.BeginTransaction(); public class Conta { private string numero; private double saldo; public void Creditar(double valor) { this.saldo = this.saldo + valor; } public void Debitar(double valor) { Código do aspecto de persistência com OleDb public class Conta { private string numero; ; } public void Debitar(double valor) {
11
Roteiro Problemas com implementações OO Conceitos de OA e Eos
Soluções baseadas em aspectos AspectC# e LOOM.NET Conclusões
12
Projeto OO ruim G D COMUNICAÇÃO I D NEGÓCIO S
Problema: entrelaçamento de código com diferentes propósitos
13
Projeto OO bom, em camadas
Interface com o usuário (GUI) Comunicação Negócio Dados
14
Melhor, em camadas com PDC (sem interfaces)
Camada de negócio Camada de dados
15
Boa modularização sem persistência, distribuição, ...
public class Programa { [STAThread] public static void Main(string[] args) { Banco fachada = Banco.GetInstance(); Programa.menu(fachada); } public static void menu(Banco fachada) { string numero = null; double valor = 0.0; Conta conta = null; int opcao = 1; while (opcao != 0) { try { System.Console.Out.WriteLine("Aperte <Enter> para continuar"); Util.Util.waitEnter(); System.Console.Out.WriteLine("\n\n\n\n\n\n\n"); System.Console.Out.WriteLine("Escolha uma das alternativas abaixo:"); System.Console.Out.WriteLine("1 - Cadastrar Conta"); System.Console.Out.WriteLine("2 - Creditar"); System.Console.Out.WriteLine("3 - Debitar"); System.Console.Out.WriteLine("4 - Transferir"); System.Console.Out.WriteLine("5 - Ver Saldo"); System.Console.Out.WriteLine("0 - Sair"); opcao = Util.Util.readInt(); switch (opcao) { Interface Negócio Dados public class Banco { private CadastroContas contas; private Banco() { contas = new CadastroConta (new RepositorioContasAccess()); } public void Cadastrar(Conta conta) { contas.Cadastrar(conta); public void Transferir(string numeroDe, string n umeroPara, double valor) { contas.Transferir(numeroDe, numeroPara, valor); public class CadastroContas { private RepositorioContas contas; public void Debitar(string numero, double valor) { Conta c = contas.Procurar(numero); c.Debitar(valor); } public void Transferir(string numeroDe, string n umeroPara, double valor) { Conta de = contas.Procurar(numeroDe); Conta para = contas.Procurar(numeroPara); de.Debitar(valor); para.Creditar(valor); public double Saldo(string numero) { return c.Saldo; public class RepositorioContasArray : RepositorioContas { private Conta[] contas; private int indice; public RepositorioContasArray() { contas = new Conta[100]; indice = 0; } public void Inserir(Conta conta) { contas[indice] = conta; indice = indice + 1; public void Atualizar(Conta conta) { int i = GetIndice(conta.Numero); if (i == indice) { throw new ContaNaoEncontradaException(conta.Numero); } else { contas[i].Atualizar(conta); public class Conta { private string numero; private double saldo; public void Creditar(double valor) { this.saldo = this.saldo + valor; } public void Debitar(double valor) { if (valor > saldo) { throw new SaldoInsuficienteException)); else { this.saldo = this.saldo - valor; public void Atualizar(Conta c) { this.numero = c.numero; this.saldo = c.saldo;
16
Mas temos problemas com persistência via OleDb
public class Banco { private CadastroContas contas; private Banco() { contas = new CadastroConta (new RepositorioContasAccess()); } public void Cadastrar(Conta conta) { Persistence.DBHandler.StartTransaction(); try { contas.Cadastrar(conta); Persistence.DBHandler.CommitTransaction(); } catch (System.Exception ex){ Persistence.DBHandler.RollBackTransaction(); throw ex; public void Transferir(string numeroDe, string n umeroPara, double valor) { contas.Transferir(numeroDe, numeroPara, valor); public class CadastroContas { private RepositorioContas contas; public void Debitar(string numero, double valor) { Conta c = contas.Procurar(numero); c.Debitar(valor); contas.Atualizar(c); } public void Transferir(string numeroDe, string n umeroPara, double valor) { Conta de = contas.Procurar(numeroDe); Conta para = contas.Procurar(numeroPara); de.Debitar(valor); para.Creditar(valor); contas.Atualizar(de); contas.Atualizar(para); public double Saldo(string numero) { return c.Saldo; public class RepositorioContasAccess : RepositorioContas { public void Inserir(Conta conta) { string sql = "INSERT INTO Conta (NUMERO,SALDO) VALUES ('" + conta.Numero + "'," + conta.Saldo + ")"; OleDbCommand insertCommand = new OleDbCommand (sql,DBHandler.Connection,DBHandler.Transaction); insertCommand.ExecuteNonQuery(); } public void Atualizar(Conta conta) { string sql = "UPDATE Conta SET SALDO = (" + conta.As ldo + ") WHERE NUMERO = '" + conta.Numero + "'"; OleDbCommand updateCommand = new OleDbCommand(s ql,DBHandler.Connection,DBHandler.Transaction); int linhasAfetadas; linhasAfetadas = updateCommand.ExecuteNonQuery(); if (linhasAfetadas == 0) { throw new ContaNaoEncontradaException(conta.Numero); public class Conta { private string numero; private double saldo; public void Creditar(double valor) { this.saldo = this.saldo + valor; } public void Debitar(double valor) { if (valor > saldo) { throw new SaldoInsuficienteException)); else { this.saldo = this.saldo - valor; public void Atualizar(Conta c) { this.numero = c.numero; this.saldo = c.saldo; public class DBHandler { private static OleDbConnection connection; public static OleDbConnection Connection { get { if (connection == null) { string dataSource = "BancoCS.mdb"; string strConexao = "Provider= Microsoft.Jet.OLEDB.4.0; " + "Data Source=" + dataSource; connection = new OleDbConnection(strConexao); } return connection; public static OleDbConnection GetOpenConnection() { Connection.Open(); return Connection; public static void StartTransaction() { transaction = Connection.BeginTransaction(); Código OleDb em vermelho…
17
Problemas com implementação OO
public class Banco { private CadastroContas contas; private Banco() { contas = new CadastroConta (new RepositorioContasAccess()); } public void Cadastrar(Conta conta) { Persistence.DBHandler.StartTransaction(); try { contas.Cadastrar(conta); Persistence.DBHandler.CommitTransaction(); } catch (System.Exception ex){ Persistence.DBHandler.RollBackTransaction(); throw ex; public void Transferir(string numeroDe, string n umeroPara, double valor) { contas.Transferir(numeroDe, numeroPara, valor); public class CadastroContas { private RepositorioContas contas; public void Debitar(string numero, double valor) { Conta c = contas.Procurar(numero); c.Debitar(valor); contas.Atualizar(c); } public void Transferir(string numeroDe, string n umeroPara, double valor) { Conta de = contas.Procurar(numeroDe); Conta para = contas.Procurar(numeroPara); de.Debitar(valor); para.Creditar(valor); contas.Atualizar(de); contas.Atualizar(para); public double Saldo(string numero) { return c.Saldo; public class DBHandler { private static OleDbConnection connection; public static OleDbConnection Connection { get { if (connection == null) { string dataSource = "BancoCS.mdb"; string strConexao = "Provider= Microsoft.Jet.OLEDB.4.0; " + "Data Source=" + dataSource; connection = new OleDbConnection(strConexao); } return connection; public static OleDbConnection GetOpenConnection() { Connection.Open(); return Connection; public static void StartTransaction() { transaction = Connection.BeginTransaction(); Entrelaçamento de código (tangling) Espalhamento de código (scattering)
18
Persistência na fachada
public class Banco { private CadastroContas contas;... public void Cadastrar(Conta conta) { try {Pers.DBHandler.StartTransaction(); contas.Cadastrar(conta); ... Pers.DBHandler.CommitTransaction(); } catch (System.Exception ex){ Pers.DBHandler.RollBackTransaction();... } }... Código de negócio misturado com transações (não pode ficar na coleção de dados)
19
Persistência na coleção de negócio
public class CadastroContas { private RepositorioContas contas;... public void Creditar(string numero, double valor) { Conta c = contas.Procurar(numero); c.Creditar(valor); contas.Atualizar(c); }... Sincronização de estados entre objetos e tabelas (registros)
20
Problemas e conseqüências
Código de persistência misturado com código de negócio Código de persistência aparece em várias classes Código difícil de manter e reusar mudanças na tecnologia de persistência serão invasivas
21
Implementação OA Código base do sistema Código do aspecto
public class Banco { private CadastroContas contas; private Banco() { contas = new CadastroConta } public void Cadastrar(Conta conta) { contas.Cadastrar(conta); public void Transferir(string numeroDe, string n umeroPara, double valor) { contas.Transferir(numeroDe, numeroPara, valor); public class CadastroContas { private RepositorioContas contas; public void Debitar(string numero, double valor) { Conta c = contas.Procurar(numero); c.Debitar(valor); } public void Transferir(string numeroDe, string n umeroPara, double valor) { Conta de = contas.Procurar(numeroDe); Conta para = contas.Procurar(numeroPara); de.Debitar(valor); para.Creditar(valor); public double Saldo(string numero) { return c.Saldo; public class Conta { private string numero; private double saldo; public void Creditar(double valor) { this.saldo = this.saldo + valor; } public void Debitar(double valor) { if (valor > saldo) { throw new SaldoInsuficienteException)); else { this.saldo = this.saldo - valor; public void Atualizar(Conta c) { this.numero = c.numero; this.saldo = c.saldo; Código base do sistema public class RepositorioContasAccess : RepositorioContas { public void Inserir(Conta conta) { string sql = "INSERT INTO Conta (NUMERO,SALDO) VALUES ('" + conta.Numero + "'," + conta.Saldo + ")"; OleDbCommand insertCommand = new OleDbCommand (sql,DBHandler.Connection,DBHandler.Transaction); insertCommand.ExecuteNonQuery(); } public void Atualizar(Conta conta) { string sql = "UPDATE Conta SET SALDO = (" + conta.As ldo + ") WHERE NUMERO = '" + conta.Numero + "'"; OleDbCommand updateCommand = new OleDbCommand(s ql,DBHandler.Connection,DBHandler.Transaction); int linhasAfetadas; linhasAfetadas = updateCommand.ExecuteNonQuery(); if (linhasAfetadas == 0) { throw new ContaNaoEncontradaException(conta.Numero); public class DBHandler { private static OleDbConnection connection; public static OleDbConnection Connection { get { if (connection == null) { string dataSource = "BancoCS.mdb"; string strConexao = "Provider= Microsoft.Jet.OLEDB.4.0; " + "Data Source=" + dataSource; connection = new OleDbConnection(strConexao); } return connection; public static OleDbConnection GetOpenConnection() { Connection.Open(); return Connection; public static void StartTransaction() { transaction = Connection.BeginTransaction(); public class Conta { private string numero; private double saldo; public void Creditar(double valor) { this.saldo = this.saldo + valor; } public void Debitar(double valor) { Código do aspecto de persistência com OleDb public class Conta { private string numero; ; } public void Debitar(double valor) {
22
Conseqüências Melhor modularidade, reuso e extensibidade
mais unidades de código mudanças na base podem causar impacto nos aspectos Separation of concerns relação entre os aspectos e o resto do sistema nem sempre é clara Normalmente menos linhas de código modularidade?
23
Tecnologia de distribução
Weaving é usado para… Compor a base do sistema com os aspectos Sistema original chamadas locais entre A e B B Aspectos de distribuição A Processo de composição Weaver Sistema distribuído chamadas remotas entre A e B A B Tecnologia de distribução
24
Composição nos join points
a method is called and returns or throws object A a method is called dispatch and returns or throws object B a method executes dispatch and returns or throws Comportamento pode ser alterado nos join points… a method executes and returns or throws Fonte: AspectJ Programming Guide
25
Pointcuts especificam join points
Identificam joint points de um sistema chamadas e execuções de métodos (e construtores) acessos a atributos tratamento de exceções inicialização estática e dinâmica Composição de joint points &&, || e !
26
Identificando chamadas de métodos
nome do pointcut pointcut writeCall(): call(public void any.Write(string)); identifica chamadas de … método Write de qualquer classe com argumento string
27
Advice especifica comportamento extra nos join points
Define código adicional que deve ser executado… before after after returning after throwing ou around join points
28
Alterando o comportamento de chamadas de métodos
qualquer chamada a Write dentro de HelloWorld após... after(): writeCall() && within(HelloWorld) { System.Console.Write(“ AOP World"); } a ação especificada será executada
29
Aspectos agrupam pointcuts, advices, propriedades, etc.
aspect HelloAOPWorld { pointcut writeCall(): call(public void any.Write(string)); after(): writeCall() && within(HelloWorld) { System.Console.Write(“ AOP World!"); }
30
Hello AOP World! Chamada afetada pelo advice, caso
public class HelloWorld { public static void Main(string[] args) { System.Console.Write(“Hello"); } Chamada afetada pelo advice, caso HelloAOPWorld tenha sido composto com HelloWorld
31
Aspecto de persistência, advices
public aspect PersistenceAspect { before(): TransMethods() { Pers.DBHandler.StartTransaction(); } after() returning(): TransMethods() { Pers.DBHandler.CommitTransaction(); after() throwing(): TransMethods() { Pers.DBHandler.RollBackTransaction(); }...
32
Além de dynamic crosscutting com advice…
Temos também static crosscutting alterar relação de subtipo adicionar membros a classes Inter-type declarations
33
Aspecto de persistência, pointcut
call versus execution pointcut TransMethods(): execution(public any Trans.any(..)); private interface Trans { public void Cadastrar(Conta conta);... } declare parents: Banco:Trans; interface local ao aspecto altera a hierarquia de tipos
34
Aspecto de persistência, pointcut, alternativa
pointcut TransMethods(): execution(public any Banco.Cadastrar(..)) || execution(public any Banco.Creditar(..)) || execution(public any Banco.Debitar(..)) || ...
35
Declaração entre tipos no aspecto de distribuição
Introduz construtor na classe indicada public SaldoInsuficienteException.new( ...SerializationInfo info, ...StreamingContext context): base(info,context) { numero = info.GetString("numero"); saldo = info.GetDouble("saldo"); }
36
Banco com controle de concorrência básico
Dados public class Banco { private CadastroContas contas; private Banco() { contas = new CadastroConta (new RepositorioContasAccess()); } public void Cadastrar(Conta conta) { contas.Cadastrar(conta); public void Transferir(string numeroDe, string n umeroPara, double valor) { contas.Transferir(numeroDe, numeroPara, valor); public class CadastroContas { private RepositorioContas contas; public void Debitar(string numero, double valor) { lock(this) { Conta c = contas.Procurar(numero); c.Debitar(valor); } public void Transferir(string numeroDe, string n umeroPara, double valor) { Conta de = contas.Procurar(numeroDe); Conta para = contas.Procurar(numeroPara); de.Debitar(valor); para.Creditar(valor); public double Saldo(string numero) { return c.Saldo; public class RepositorioContasArray : RepositorioContas { private Conta[] contas; private int indice; public RepositorioContasArray() { contas = new Conta[100]; indice = 0; } public void Inserir(Conta conta) { contas[indice] = conta; indice = indice + 1; public void Atualizar(Conta conta) { int i = GetIndice(conta.Numero); if (i == indice) { throw new ContaNaoEncontradaException(conta.Numero); } else { if (conta.Timestamp == contas[I].Timestamp) { contas[i].Atualizar(conta); Conta.incTimestamp(); } else {………….}} public class Conta { private string numero; private double saldo; Private long timestamp; public void Creditar(double valor) { this.saldo = this.saldo + valor; } public void Debitar(double valor) { if (valor > saldo) { throw new SaldoInsuficienteException)); else { this.saldo = this.saldo - valor; public void Atualizar(Conta c) { this.numero = c.numero; this.saldo = c.saldo; this.timestamp = c.timestamp; Negócio Concorrência
37
Controle de concorrência na coleção de negócio
public void Debitar(string n, double v) { lock(this) {... Conta c = contas.Procurar(n); ... c.Debitar(v); } }... Controle de concorrência para evitar interferências indesejadas entre os métodos da fachada
38
Controle de concorrência na coleção de dados
public void Atualizar(Conta conta) { ... c = contas[i]; if (conta.Timestamp == c.Timestamp) { c.Atualizar(conta); c.UpdateTimestamp(); } else {...} }... Controle de concorrência para evitar manipulação de versões desatualizadas de objetos
39
Controle de concorrência na classe básica
public class Conta { private double saldo;... private long timestamp; public void Atualizar(Conta c) { this.saldo = c.saldo;... this.timestamp = c.timestamp; }... } Controle otimista de concorrência
40
Os pointcuts podem expor o contexto dos join points
Informações disponíveis nos join points argumentos de métodos objetos responsáveis pela execução objetos alvo variáveis de instância
41
Aspecto de concorrência, pointcut
Informação exposta public aspect ConcurrencyAspect { pointcut ConcurrentMethods(object t): ((call(void CadContas.Cadastrar(Conta)) && target(t)) || ... ); Associação de t com o alvo da chamada de método
42
Aspecto de concorrência, advice
O corpo do around poderá usar a informação exposta Object around(Object t): ConcurrentMethods(t) { Object obj; lock (t) { obj = proceed(t); } return obj; A execução do join point interceptado deve continuar
43
Aspecto de persistência, outro advice
atribuições à variável de instância ou estática void around(Banco b): fset(CadastroContas Banco.contas) && execution(private Banco.new()) && this(b) { b.contas = new CadastroContas( new RepositorioContasAccess()); } Associação de b com o objeto sendo inicializado
44
Quebra de encapsulamento
void around(Banco b): fset(CadastroContas Banco.contas) && execution(private Banco.new()) && this(b) { b.contas = new CadastroContas( new RepositorioContasAccess()); } Variável de instância privada! Aspecto deve ser definido como privileged
45
Banco remoto com .NET Remoting
Distribuição Dados Interface Negócio public class Programa { [STAThread] public static void Main(string[] args) { Banco fachada; try { TcpChannel chan = new TcpChannel(); (Banco)Activator.GetObject(typeof(Fachada.Banco), System.Console.WriteLine("Could not locate server"); } else { Programa.menu(fachada); } } catch (Exception e) { System.Console.WriteLine("The error was: " + e.Message); } } public static void menu(Banco fachada) { string numero = null; while (opcao != 0) { System.Console.Out.WriteLine("Aperte <Enter> para continuar"); Util.Util.waitEnter(); System.Console.Out.WriteLine("\n\n\n\n\n\n\n"); System.Console.Out.WriteLine("2 - Creditar"); …} catch (Exception exception) { System.Console.Out.WriteLine(exception.Message); public class ServerInit { public static void Main(string[] args) { try { TcpChannel chan = new TcpChannel(8085); ChannelServices.RegisterChannel(chan); RemotingConfiguration.RegisterWellKnownServiceType (Type.GetType("Fachada.Banco"), } catch (Exception e) { Console.WriteLine("An error has happened:"); Console.WriteLine(e.Message); } public class Banco: System.MarshalByRefObject { private CadastroContas contas; private Banco() { contas = new CadastroConta (new RepositorioContasAccess()); } public void Cadastrar(Conta conta) { contas.Cadastrar(conta); public void Transferir(string numeroDe, string n umeroPara, double valor) { contas.Transferir(numeroDe, numeroPara, valor); public class CadastroContas { private RepositorioContas contas; public void Debitar(string numero, double valor) { Conta c = contas.Procurar(numero); c.Debitar(valor); contas.Atualizar(c); } public void Transferir(string numeroDe, string n umeroPara, double valor) { Conta de = contas.Procurar(numeroDe); Conta para = contas.Procurar(numeroPara); de.Debitar(valor); para.Creditar(valor); contas.Atualizar(de); contas.Atualizar(para); public double Saldo(string numero) { return c.Saldo; public class RepositorioContasArray : RepositorioContas { private Conta[] contas; private int indice; public RepositorioContasArray() { contas = new Conta[100]; indice = 0; } public void Inserir(Conta conta) { contas[indice] = conta; indice = indice + 1; public void Atualizar(Conta conta) { int i = GetIndice(conta.Numero); if (i == indice) { throw new ContaNaoEncontradaException(conta.Numero); } else { contas[i].Atualizar(conta); [System.Serializable()]public class Conta { private string numero; private double saldo; public void Creditar(double valor) { this.saldo = this.saldo + valor; } public void Debitar(double valor) { if (valor > saldo) { throw new SaldoInsuficienteException)); else { this.saldo = this.saldo - valor; public void Atualizar(Conta c) { this.numero = c.numero; this.saldo = c.saldo; [System.Serializable()] public class ContaJaCadastradaException : System.Exception { public string Numero { get { return numero; } } private string numero; public ContaJaCadastradaException(numero; } public ContaJaCadastradaExceptionnumero = info.GetString("numero"); public override void GetObjectData(base. GetObjectData(info,context); info.AddValue("numero", numero,typeo f(string)); }}
46
Distribuição na interface com o usuário
public static void Main(string[] args) { Banco fachada; try {... fachada = (Banco) Activator.GetObject( typeof(Fachada.Banco), "tcp://localhost:8085/BancoRemoto"); ... Programa.menu(fachada); } catch... } serviço de lookup
47
Distribuição na fachada
public class Banco: System.MarshalByRefObject { private CadastroContas contas; private static Banco banco; Supertipo de qualquer servidor Manipulação de objetos por valor versus por referência
48
Distribuição na classe básica e exceções
[System.Serializable()] public class Conta { private double saldo;...} public class ContaNaoEncontradaException : System.Exception {...} Possibilita a passagem de objetos por valor
49
Aspecto de distribuição, servidor
public aspect DistributionAspectServer { declare parents: Banco:System.MarshalByRefObject; } Temos dois aspectos apenas por questões de implantação
50
Aspecto de distribuição, cliente
Acrescenta atributos a uma classe aspect DistributionAspectClient { declare class attributes: (Conta || SaldoInsuficienteException) [System.Serializable()]; ...
51
Aspecto de distribuição
void around(): execution(...void Programa.Main(string[])) { Banco fachada; try {... fachada = (Banco) Activator.GetObject( typeof(Fachada.Banco), "tcp://localhost:8085/BancoRemoto"); ...Programa.menu(fachada); } catch... }
52
O aspecto de sincronização de estado é...
Útil tanto para persistência quanto para distribuição Dividido em duas partes: registro de objetos modificados (sujos) atualização dos objetos modificados
53
Registro de objetos modificados
Quaisquer argumentos pointcut localUpdate(Conta c): this(CadContas) && target(c) && (call(any Conta.Creditar(..)) || ...; private ArrayList dirtyObjects = ...; after(Conta c) returning(): localUpdate(c) { dirtyObjects.add(c); }
54
Atualização dos objetos modificados
pointcut localExecution(CadContas cad): if(HasDirtyObjects()) && this(cad) && execution(public any any(..)); after(CadContas cad) returning(): localExecution(cad) { foreach (Conta c in dirtyObjects) { cad.Contas.Atualizar(c); }
55
Aspecto de sincronização de estado
publics omitidos... privileged aspect StateSynchronization percflow(execution(any Banco.any(..))) { RepositorioContas CadastroContas.Contas { get { return this.contas; } Para evitar interferências no atributo do aspecto Adiciona propriedade
56
Instâncias de aspectos
default, apenas uma instância, aspecto estático percflow, uma instância para cada fluxo de um joint point pertarget, uma instância para cada alvo de um joint point pertthis percflowbelow
57
Outros pointcut designators
cflow(<pointcut>) todos os join points no fluxo de controle do <pointcut> cflowbelow(<pointcut>) todos os join points no fluxo de controle do <pointcut>, exceto o inicial fget(<signature>) todos os join points dos acessos às variáveis com assinatura <signature>
58
Mais pointcut designators
withincode(<method>) todos os join points do código que aparece dentro de um método initialization(<constructor>) todos os join points de inicialização com uma dada assinatura args(<Type or Id, ...>) todos os join points com argumentos dos tipos especificados
59
Mais construções de Eos
NomeAspecto.aspectOf() retorna a instância de um determinado aspecto, útil para acesso a membros do aspecto declare precedence: <TypeList> define a precedência entre aspectos que afetam um mesmo join point
60
Advices só para instâncias específicas
instancelevel modificador de advice e aspecto advice ou aspecto só afetará instâncias registradas pelos métodos abaixo addObject removeObject
61
Selecionando instâncias
public aspect Trace { public void Select(Bit bit) { addObject(bit); } after():execution(public any any.any()) { Console.WriteLine("In any method"); instancelevel after(): execution(public bool Bit.Get()) { Console.WriteLine(“A selective advice"); }... Fonte: Eos distribution
62
Sincronização entre conjuntos, aspecto
public instancelevel aspect Bijection { bool busy; Set A; Set B; public void Relate(Set A, Set B) { addObject(A); addObject(B); this.A = A; this.B = B; } Fonte: Eos distribution
63
Sincronização entre conjuntos, advice
after():execution(public bool Set.Insert()) { ...r = (bool) thisJoinPoint.getReturnValue(); if(r) { Set set = (Set) thisJoinPoint.getTarget(); object[] args = thisJoinPoint.getArgs(); Element e = (Element)arguments[0]; if (set == this.A) B.Insert(e); else A.Insert(e); } }... Fonte: Eos distribution
64
Sincronização entre conjuntos, inicialização
public static void Main (string[] argument) { Set A = new Set(); Set B = new Set(); Bijection bj = new Bijection(); bj.Relate(A,B); Element A1 = new Element("A1"); A.Insert(A1); Element B1 = new Element("B1"); B.Insert(B1);... } Fonte: Eos distribution
65
Acessando mais informações dos join points
Além das informações expostas pelos pointcuts, é possível acessar mais sobre os join points usando referências especiais: thisJoinPoint thisJoinPointStaticPart
66
Métodos das referências especiais
thisJoinPoint getArgs() getTarget() getReturnValue() thisJoinPointStaticPart getSignature()
67
Debugging ou logging simples
public aspect LoggingAspect { before(): execution(public any any.any(..)) { System.Console.Write("A method from..." + thisJoinPoint.getTarget() + " is about" + “ to be executed. Its signature is " + thisJoinPointStaticPart.getSignature()); }
68
Aspecto de desenvolvimento versus produção
after(): execution(public any any.any(..)) { System.Console.Write("Now the method" + ... + " has finished"); ... System.Console.Write("The return value was “ + thisJoinPoint.getReturnValue()); }
69
Abordagens para aspectos com C#
Eos baseada em uma extensão de C# com novos recursos linguísticos AspectC# baseada em XMLs que descrevem como classes C# devem ser compostas LOOM.NET baseada em API e atributos C# que descrevem como classes C# devem ser compostas
70
Orientação a aspectos é...
Quantificação (quantification) uma parte do programa tem efeito em várias outras o aspecto afeta várias classes e outros aspectos Mudanças não invasivas (obliviouness) uma parte A do programa tem efeito sobre uma B sem precisar alterar o código de B
71
AspectC# Advices disponíveis: before, after e around
Acesso reflexivo ao contexto do join point Falta quantificação
72
AspectC#, localização da base e dos aspectos
<TargetBase>c:\...</TargetBase> <AspectBase>c:\...</AspectBase>
73
AspectC#, definição do aspecto (advice)
... <Aspect-Method> <Name>AspectoSincronizacao</Name> <Namespace>Contas</Namespace> <Class>AspectoSincronizacao</Class> <Method>Sincronizar()</Method> </Aspect-Method>
74
AspectC#, definição da classe afetada (pointcut)
...<Target> <Namespace>Contas</Namespace> <Class>CadContas</Class> <Method> <Name>Cadastrar()</Name> <Type>before</Type> <Aspect-Name>AspectoSincronizacao </Aspect-Name></Method></Target></Aspect>
75
LOOM.NET Advices disponíveis: before, after e instead (around)
proceed(context) Aspectos são classes que herdam de Aspect Suporte a quantificação (wildcards) É invasiva
76
Métodos afetados têm que ser virtual
LOOM.NET, invasão public class HelloWorld { public virtual void SayHello() { System.Console.WriteLine("Hello World"); } public virtual void SayBye() { System.Console.WriteLine("Bye World"); Métodos afetados têm que ser virtual
77
LOOM.NET, aspecto public class LoggingAspect:Aspect { [Call(Invoke.After)] public void SayBye() { System.Console.Write("SayBye! <-"); }... Corpo do método é o corpo do advice; atributo e nome do método são o pointcut e tipo do advice
78
LOOM.NET, quantificação
Nome do método deixa de contribuir para o pointcut [Call(Invoke.Before,Alias="Say*")] public void Say() { System.Console.Write(“-> SayHello!"); }
79
LOOM.NET, mais invasão class MainClass { [STAThread]
public static void Main(string[] args) { HelloWorld h = (HelloWorld) Weaver.CreateInstance( typeof(HelloWorld), null,new LoggingAspect()); h.SayHello();... }...
80
AOP ou um bom projeto OO? Decorator ou Adapter
81
Com padrões (adapter ou decorator)…
Escrevemos mais código A ligação entre o adaptador e o objeto adaptado é explicita e invasiva não altera o comportamento de chamadas internas para o objeto adaptado não tem acesso ao objeto fonte (source) pode ser modificado dinamicamente
82
Reuso e extensibilidade de aspectos via padrões e frameworks
Tag interface como na interface Trans do aspecto de transações Glue aspects advices invocando serviços auxiliares Template pointcut com aspectos abstratos
83
Aspecto abstrato para persistência
public abstract aspect APersistenceAspect { abstract pointcut TransactionalMethods(); before(): TransactionalMethods() { Pers.DBHandler.StartTransaction(); }... }
84
Aspecto concreto para persistência
public aspect PersistenceAspect: APersistenceAspect { private interface Trans { public void Cadastrar(Conta conta);... } declare parents: Banco:Trans; override pointcut TransactionalMethods(): execution(public any Trans.any(..));
85
Aspectos, pontos positivos
Útil para implementar crosscutting concerns Modularidade, reuso, e extensibilidade de software Produtividade Separação na implementação e testes (plug-in/out)
86
Aspectos, pontos negativos
Modularidade relativa falta noção de interface Dependência entre classes e aspectos sensível a refactorings Necessidade de refactorings para expor join points É essencial usar IDE Conflitos entre aspectos
87
Tópicos de pesquisa Orientação a aspectos modular Novos joint points
entendimento das partes leva ao entendimento do todo; não é preciso expandir... Novos joint points Processo de desenvolvimento Linhas de produtos de software
88
Referências Ver roteiro de exercícios ...
Apresentações semelhantes
© 2024 SlidePlayer.com.br Inc.
All rights reserved.