1 / 88

Programação orientada a aspectos com C#

Programação orientada a aspectos com C#. Paulo Borba e André Furtado Centro de Informática Universidade Federal de Pernambuco. Programação orientada a aspectos é. uma nova técnica de programação que oferece suporte à modularização de crosscutting concerns.

arvin
Télécharger la présentation

Programação orientada a aspectos com C#

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


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

  10. Com aspectos 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) { Conta c = contas.Procurar(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() { 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) { 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) { 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 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) { Persistence.DBHandler.StartTransaction(); try { contas.Transferir(numeroDe, numeroPara, valor); Persistence.DBHandler.CommitTransaction(); } catch (System.Exception ex){ Persistence.DBHandler.RollBackTransaction(); throw ex; } } } 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 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() { Connection.Open(); transaction = Connection.BeginTransaction(); } } Código OleDb em vermelho…

  17. Problemas com implementação OO 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 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 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; } } } 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ênciaaparece 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 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) { Conta c = contas.Procurar(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() { 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) { 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. B Weaving é usado para… • Compor a base do sistema com os aspectos Aspectos de distribuição Sistema original chamadas locais entre A e B A Processo de composição Weaver Sistema distribuído chamadas remotas entre A e B A B Tecnologia de distribução

  24. a method is called a method is called a method executes a method executes Composição nos join points and returns or throws object A dispatch and returnsor throws object B dispatch and returns or throws Comportamento pode seralterado nos join points… 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étodoWrite 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! 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) { 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 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 voidaround(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 voidaround(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) { 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("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) { 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); } } [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;...} [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 Acrescenta atributos a uma classe aspect DistributionAspectClient { declare class attributes: (Conta ||SaldoInsuficienteException) [System.Serializable()]; ...

More Related