A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Programação orientada a aspectos com C# Paulo Borba e André Furtado Centro de Informática Universidade Federal de Pernambuco.

Apresentações semelhantes


Apresentação em tema: "Programação orientada a aspectos com C# Paulo Borba e André Furtado Centro de Informática Universidade Federal de Pernambuco."— Transcrição da apresentação:

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 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 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 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) { Conta c = contas.Procurar(numero); return c.Saldo; } 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) { Persistence.DBHandler.StartTransaction(); try { contas.Transferir(numeroDe, numeroPara, valor); Persistence.DBHandler.CommitTransaction(); } catch (System.Exception ex){ Persistence.DBHandler.RollBackTransaction(); throw ex; } } 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() { Connection.Open(); 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 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 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 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) { Conta c = contas.Procurar(numero); return c.Saldo; } 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) { Persistence.DBHandler.StartTransaction(); try { contas.Transferir(numeroDe, numeroPara, valor); Persistence.DBHandler.CommitTransaction(); } catch (System.Exception ex){ Persistence.DBHandler.RollBackTransaction(); throw ex; } } 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() { Connection.Open(); transaction = Connection.BeginTransaction(); }

10 Com aspectos 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 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 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) { Conta c = contas.Procurar(numero); return c.Saldo; } 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 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() { Connection.Open(); 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) { public class Conta { private string numero; ; } public void Debitar(double valor) { Código base do sistema Código do aspecto de persistência com OleDb

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 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 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) { Conta c = contas.Procurar(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 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 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) { 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); } } Interface Negócio Dados

16 Mas temos problemas com persistência via OleDb 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 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 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) { Conta c = contas.Procurar(numero); return c.Saldo; } 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) { Persistence.DBHandler.StartTransaction(); try { contas.Transferir(numeroDe, numeroPara, valor); Persistence.DBHandler.CommitTransaction(); } catch (System.Exception ex){ Persistence.DBHandler.RollBackTransaction(); throw ex; } } 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() { Connection.Open(); transaction = Connection.BeginTransaction(); } Código OleDb em vermelho…

17 Problemas com implementação OO 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) { Conta c = contas.Procurar(numero); return c.Saldo; } 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) { Persistence.DBHandler.StartTransaction(); try { contas.Transferir(numeroDe, numeroPara, valor); Persistence.DBHandler.CommitTransaction(); } catch (System.Exception ex){ Persistence.DBHandler.RollBackTransaction(); throw ex; } } 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() { Connection.Open(); transaction = Connection.BeginTransaction(); } Espalhamento de código (scattering) Entrelaçamento de código (tangling)

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 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 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 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) { Conta c = contas.Procurar(numero); return c.Saldo; } 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 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() { Connection.Open(); 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) { public class Conta { private string numero; ; } public void Debitar(double valor) { Código base do sistema Código do aspecto de persistência com OleDb

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 W eaving é usado para… Compor a base do sistema com os aspectos A B Tecnologia de distribução Sistema original chamadas locais entre A e B Sistema distribuído chamadas remotas entre A e B Weaver Processo de composição Aspectos de distribuição AB

24 Composição nos join points object A object B and returns or throws a method is called dispatch a method is called and returns or throws a method executes and returns or throws a method executes and returns or throws Comportamento pode ser alterado nos join points… 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 pointcut writeCall(): call(public void any.Write(string)); com argumento string método Write de qualquer classe identifica chamadas de … nome do pointcut

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 after(): writeCall() && within(HelloWorld) { System.Console.Write( AOP World"); } após... qualquer chamada a Write dentro de HelloWorld 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! 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 pointcut TransMethods(): execution(public any Trans.any(..)); private interface Trans { public void Cadastrar(Conta conta);... } declare parents: Banco:Trans; altera a hierarquia de tipos interface local ao aspecto call versus execution

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 public SaldoInsuficienteException.new(...SerializationInfo info,...StreamingContext context): base(info,context) { numero = info.GetString("numero"); saldo = info.GetDouble("saldo"); } Introduz construtor na classe indicada

36 Banco com controle de concorrência básico 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; } 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) { lock(this) { Conta de = contas.Procurar(numeroDe); Conta para = contas.Procurar(numeroPara); de.Debitar(valor); para.Creditar(valor); } public double Saldo(string numero) { Conta c = contas.Procurar(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 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); } } Dados 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 public aspect ConcurrencyAspect { pointcut ConcurrentMethods(object t): ((call(void CadContas.Cadastrar(Conta)) && target(t)) ||... ); Informação exposta Associação de t com o alvo da chamada de método

42 Aspecto de concorrência, advice Object around(Object t): ConcurrentMethods(t) { Object obj; lock (t) { obj = proceed(t); } return obj; } O corpo do around poderá usar a informação exposta A execução do join point interceptado deve continuar

43 Aspecto de persistência, outro advice void around(Banco b): fset(CadastroContas Banco.contas) && execution(private Banco.new()) && this(b) { b.contas = new CadastroContas( new RepositorioContasAccess()); } atribuições à variável de instância ou estática 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 [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; } 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 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) { try { System.Console.Out.WriteLine("Aperte 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 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) { Conta c = contas.Procurar(numero); return c.Saldo; } 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); } [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)); }} Interface Negócio Distribuição Dados

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;...} [System.Serializable()] 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 aspect DistributionAspectClient { declare class attributes: (Conta || SaldoInsuficienteException) [System.Serializable()];... Acrescenta atributos a uma classe

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 pointcut localUpdate(Conta c): this(CadContas) && target(c) && (call(any Conta.Creditar(..)) ||...; private ArrayList dirtyObjects =...; after(Conta c) returning(): localUpdate(c) { dirtyObjects.add(c); } Quaisquer argumentos

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 privileged aspect StateSynchronization percflow(execution(any Banco.any(..))) { RepositorioContas CadastroContas.Contas { get { return this.contas; } publics omitidos... 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 cflow( ) todos os join points no fluxo de controle do cflowbelow( ) todos os join points no fluxo de controle do, exceto o inicial fget( ) todos os join points dos acessos às variáveis com assinatura Outros pointcut designators

58 withincode( ) todos os join points do código que aparece dentro de um método initialization( ) todos os join points de inicialização com uma dada assinatura args( ) todos os join points com argumentos dos tipos especificados Mais pointcut designators

59 NomeAspecto.aspectOf() retorna a instância de um determinado aspecto, útil para acesso a membros do aspecto declare precedence: define a precedência entre aspectos que afetam um mesmo join point Mais construções de Eos

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 Fonte: Eos distribution 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"); }...

62 Sincronização entre conjuntos, aspecto Fonte: Eos distribution 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; }

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 Fonte: Eos distribution 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);... }

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 c:\...

73 AspectC#, definição do aspecto (advice)... AspectoSincronizacao Contas AspectoSincronizacao Sincronizar()

74 AspectC#, definição da classe afetada (pointcut)... Contas CadContas Cadastrar() before AspectoSincronizacao

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 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 [Call(Invoke.Before,Alias="Say*")] public void Say() { System.Console.Write(-> SayHello!"); } Nome do método deixa de contribuir para o pointcut

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 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...


Carregar ppt "Programação orientada a aspectos com C# Paulo Borba e André Furtado Centro de Informática Universidade Federal de Pernambuco."

Apresentações semelhantes


Anúncios Google