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

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

Programação orientada a aspectos com C#

Apresentações semelhantes


Apresentação em tema: "Programação orientada a aspectos com C#"— 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 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 ...


Carregar ppt "Programação orientada a aspectos com C#"

Apresentações semelhantes


Anúncios Google