programação orientada a objetos - pós graduação - aula 7 - inversão de controle
TRANSCRIPT
Programação Orientada a Objetos
Inversão de Controle
Pós Graduação em Análise e Desenvolvimento de Sistemas
Aplicados à Gestão Empresarial
INSTITUTO FEDERAL DE EDUCAÇÃO, CIÊNCIA E TECNOLOGIA
TRIÂNGULO MINEIRO – Campus Uberlândia Centro
Prof Carlos Eduardo Dantas – [email protected]
Prof Carlos Eduardo Dantas – [email protected]
Separação de responsabilidades
• Ao pensar no design de uma aplicação, deve-se pensar no grupo de objetos que trabalham em conjunto para uma determinada finalidade;
• Ao desenhar pequenas classes que, juntas, realizam uma tarefa maior, o programador ganha em simplicidade e modularidade;
• Sistemas fáceis de manter são os que contém classes que possuem apenas uma responsabilidade bem definida, já que a alteração do comportamento é isolada.
Prof Carlos Eduardo Dantas – [email protected]
Baixo acoplamento e alta coesão
• O desejável é que mudanças em uma parte do sistema não impliquem em mudanças em outras partes;
• A necessidade de atualizar diversos pontos do código em alterar uma funcionalidade indica que estes pontos estão ligados ou acoplados de maneira indesejada;
• Acoplamento é o quanto dois elementos estão amarrados entre si e quanto as alterações no comportamento de um afetam o de outro.
Prof Carlos Eduardo Dantas – [email protected]
Baixo acoplamento e alta coesão
• Minimizar o acoplamento implica em facilitar a troca dos componentes, além de ser peça fundamental para a manutenção do código, formando um arquitetura de maior qualidade;
• Baixo acoplamento é diferente de Nenhumacoplamento;
• Deseja-se que a ligação entre dois componentes seja a menor e mais simples possível;
Prof Carlos Eduardo Dantas – [email protected]
Baixo acoplamento e alta coesão
• A razão da existência de todo componente é exercer algum tipo de função ou responsabilidade dentro do sistema, por isso este deve ter alta coesão;
• Alta coesão quer dizer que suas responsabilidades sejam relacionadas e façam sentido juntas, que não haja responsabilidades desconexas dentro de um mesmo componente;
• SRP – uma única razão para mudança.
Prof Carlos Eduardo Dantas – [email protected]
Baixo acoplamento e alta coesão
• Um método que verifica permissões de um usuário logado e monta um relatório possui mais de uma responsabilidade e requer refatoração;
• Separar indica criar dois métodos distintos, e até duas classes distintas, pois duas responsabilidades estão vinculadas: autenticação e execução.
Prof Carlos Eduardo Dantas – [email protected]
Injeção de Dependências
• Mesmo com o baixo acoplamento, sempre existirá uma ligação entre duas classes que precisam trabalhar em conjunto.
Prof Carlos Eduardo Dantas – [email protected]
Injeção de Dependências
• No exemplo anterior, Dao existe para que se encapsule os detalhes de acesso a dados, contudo precisa de recursos para realizar seu trabalho, como conexão com o banco.
Prof Carlos Eduardo Dantas – [email protected]
Injeção de Dependências
• É inviável repetir o código de conexão, e outros detalhes como externalização de configurações, pool de conexões, etc.. É óbvio que ProjetoDao tem responsabilidades demais.
Prof Carlos Eduardo Dantas – [email protected]
Injeção de Dependências
• No último exemplo, não seria possível salvar dois projetos com a mesma conexão, nem executar dois métodos Dao em uma única transação.
• Essa é uma má prática conhecida como sessão por operação, ou transação por operação;
• Esse exemplo soa
familiar?
Prof Carlos Eduardo Dantas – [email protected]
Injeção de Dependências
• Neste exemplo, o Dao acabaria com uma grande quantidade de métodos, a maioria formado por uma combinação de outros, ou seja, o Dao trabalha demais.
Prof Carlos Eduardo Dantas – [email protected]
Injeção de Dependências
• O problema deste exemplo é se o método inicia() for esquecido de ser invocado, ou seja, o objetoDao não é um bom cidadão, já que pode ser instanciado sem que todas as suas dependências sejam resolvidas.
Prof Carlos Eduardo Dantas – [email protected]
Injeção de Dependências
• O método fecha() quebra o encapsulamento do Dao, já que se a implementação for trocada por outros tipos de arquivos, não existiria conexão a ser fechada;
• Deve-se evitar espalhar responsabilidade de gerenciar o recurso que está sendo manipulado;
• Não existe erro de compilação por não chamar o método fecha();
• Delegar fechamento de conexão para outras classes é ruim porque o fechamento é relativamente complexo, pois deve-se controlar transações e exceções;
• Ainda não é possível salvar um Projeto, atualizar um Usuário e remover uma História, já que cada Dao abre sua conexão.
Prof Carlos Eduardo Dantas – [email protected]
Injeção de Dependências
• A solução é tirar do Dao a responsabilidade de abrir e fechar conexões;
• Sua única responsabilidade será tratar das operações de manipulação do banco, mas não irá gerenciar conexões.
Prof Carlos Eduardo Dantas – [email protected]
Injeção de Dependências
• Receber a conexão em vez de criá-la é um princípio de injeção de dependências;
• Inverte-se quem está no controle de gerenciar a dependência;
• O programador faz com que os objetos já recebam suas dependências inicializados e prontos para uso;
Prof Carlos Eduardo Dantas – [email protected]
Inversão de Controle vsInjeção de Dependências
• Injeção de Dependências é um caso específico de Inversão de Controle;
• Em uma aplicação visual, ao invés de verificar o estado de um botão de tempos em tempos, uma classe pode registrar um listener, que será notificado quando o evento ocorrer, onde o código do tratamento do evento passa a ser invocado pelo botão, em vez de invocar métodos para descobrir seu estado.
Prof Carlos Eduardo Dantas – [email protected]
Injeção de Dependências
• Diante disso, quem irá gerenciar a conexão?
• Na injeção de dependências, existe um dependente (o Dao), uma dependência (a conexão), e quem amarra tudo isso é um provedor (provider).
Prof Carlos Eduardo Dantas – [email protected]
Injeção de Dependências
• Inverter o controle e declarar as dependências para ser injetadas por alguém é considerado uma boa prática de design;
• As dependências podem ser injetadas via construtor, métodos setter, ou diretamente nos atributos via reflection;
• O mais recomendado é via construtor.
Prof Carlos Eduardo Dantas – [email protected]
Injeção de Dependências
• Injeção diretamente no atributo:
• Injeção via setter:
Prof Carlos Eduardo Dantas – [email protected]
Injeção de Dependências
• Em CrudDao, foi implementada uma estratégia manual de injeção de dependências.
Prof Carlos Eduardo Dantas – [email protected]
Injeção de Dependências
• Em ClienteControl, não existe inversão de controle, pois esta classe sabe onde buscar suas dependências, pelo ServiceLocator.
Prof Carlos Eduardo Dantas – [email protected]
Injeção de Dependências
• Contudo, muitos têm utilizado frameworks que fazem a injeção automaticamente, como Spring, Google Guice, Pico Container, e a especificação CDI do Java EE 6, com o framework Weld como implementação de referência;
• Na disciplina “Desenvolvimento de Sistemas”, será usado o CDI com o framework Weld.
Prof Carlos Eduardo Dantas – [email protected]
Refactoring com IoC na camada Dao do Ecommerce
• Será aplicada uma inversão de controle manual no projeto utilizado nas aulas anteriores;
• Observa-se no código abaixo que está sendo implementado a má prática chamada transação
por operação.
Prof Carlos Eduardo Dantas – [email protected]
Refactoring com IoC na camada Dao do Ecommerce
• Caso o sistema necessite salvar dois clientes ou dois pedidos em uma mesma transação, ou ainda assim salvar um cliente e um pedido na mesma transação, não será possível;
• Para exemplificar este cenário, será criada uma classe Log, que será salva juntamente com Cliente e Pedido.
Prof Carlos Eduardo Dantas – [email protected]
Refactoring com IoC na camada Dao do Ecommerce
Prof Carlos Eduardo Dantas – [email protected]
Refactoring com IoC na camada Dao do Ecommerce
• Deseja-se que a classe CrudDaoImpl deixe de ter a responsabilidade de gerenciar as conexões;
• Esta classe simplesmente irá usar as conexões para efetuar suas operações;
• Contudo, as conexões deverão ser estado nas classes PedidoDao,ClienteDao e LogDao, pois estas classes podem efetuar outras operações com o banco de dados, como uma consulta complexa via Sql. CrudDaoImpl somente faz operações de CRUD.
Prof Carlos Eduardo Dantas – [email protected]
Refactoring com IoC na camada Dao do Ecommerce
• Adiciona-se o método getEntityManager() em Crudavel
Prof Carlos Eduardo Dantas – [email protected]
Refactoring com IoC na camada Dao do Ecommerce
• Inverte-se o controle do Dao, exigindo que as classes recebam a EntityManager ao serem instanciadas.
Prof Carlos Eduardo Dantas – [email protected]
Refactoring com IoC na camada Dao do Ecommerce
• O mesmo é feito com LogDao. Os métodos getConsultaSql() e getParametrosMapa() receberão implementação quando for criado algo para consultar o log.
Prof Carlos Eduardo Dantas – [email protected]
Refactoring com IoC na camada Dao do Ecommerce
• Observa-se que CrudDaoImpl apenas usa o EntityManager, não gerencia mais a conexão
Prof Carlos Eduardo Dantas – [email protected]
Refactoring com IoC na camada Dao do Ecommerce
• Obviamente as classes do pacote servicecomeçam a gerar erros, pois o Dao está exigindo a EntityManager para efetuar seu trabalho;
• O gerenciamento das conexões não pode ser feito pelas classes de service, pois estas classes somente servem para expor o model para clientes remotos. Deverá ser criada outra chamada chamada repository.
Prof Carlos Eduardo Dantas – [email protected]
Refactoring com IoC na camada Dao do Ecommerce
• Será criada uma exception para identificar erros de sistema.
Prof Carlos Eduardo Dantas – [email protected]
Refactoring com IoC na camada Dao do Ecommerce
• Será criada uma exception para identificar erros de sistema.
Prof Carlos Eduardo Dantas – [email protected]
Refactoring com IoC na camada Dao do Ecommerce
• O repositório de Cliente pode ser feito dessa forma:
Prof Carlos Eduardo Dantas – [email protected]
Refactoring com IoC na camada Dao do Ecommerce
Prof Carlos Eduardo Dantas – [email protected]
Refactoring com IoC na camada Dao do Ecommerce
• Ao executar o sistema, naturalmente um erro será gerado porque a tabela TB_LOG não existe, contudo como foi feito um rollback, o cliente também não foi inserido.
Prof Carlos Eduardo Dantas – [email protected]
Refactoring com IoC na camada Dao do Ecommerce
• Ao editar o arquivo persistence.xml para permitir dropar e criar tabelas, a tabela TB_LOG irá existir, logo o insert será feito em ambas as tabelas.
Prof Carlos Eduardo Dantas – [email protected]
Referências
• SILVEIRA, Paulo, Guilherme. LOPES, Sérgio. MOREIRA, Guilherme, SEPPAT, Nico. KUNG, Fábio. Introdução à Arquitetura e Design de Software. Editora Campus, 2012;
• ANICHE, Maurício. Orientação a objetos e SOLID para Ninjas. Casa do Código, 2015;
• GUERRA, Eduardo. Design Patterns com Java. Casa do Código, 2014;
• “LARMAN, Craig – Utilizando UML e Padrões 3ª Edição. Bookman, 2007”.