[MÚSICA] [MÚSICA] Olá a todos! O meu nome é Eduardo Guerra. Esse é o curso de desenvolvimento ágil com padrões de projeto. Na aula passada, a gente viu pouquinho sobre proxies e decorations. Mas eu acho que é nessa aula que você vai ver como que o padrão é fantástico. Eu vou mostrar alguns exemplos aí de proxies para vocês verem como dá para fazer coisas muito legais usando esse padrão. Então eu espero que, a partir desses exemplos mais concretos, vocês realmente vejam o valor que esse padrão, como ele pode ser utilizado para deixar o software mais modularizado, de forma que você possa por exemplo acrescentar novas funcionalidades sem ter que modificar a classe. Vamos lá! Bom, o primeiro exemplo que eu vou mostrar aqui é para fazer cache dos resultados de métodos. Imagine que você tem uma classe e você quer por exemplo que você chama várias vezes, vamos supor que é uma classe que faz acesso remoto ou uma classe que busca no banco de dados e você quer otimizar, você quer guardar resultados que você já perguntou para ela, guardar esses resultados para você não ter que processar tudo aquilo de novo. Vamos ver como é que seria isso daí. Imagine que eu tenha ali uma classe que acessa o banco de dados, o DAO que tem por exemplo recuperar, excluir e gravar. Eu tenho de lado ali o meu DAO concreto e eu vou ter ali o meu proxy, que vai ser o meu cache proxy que vai estar armazenando esses resultados das chamadas já realizadas. Vamos ver como é que seria o código disso daí. Então eu tenho aí o código. Vocês podem ver. Eu vou explicar pedacinho por pedacinho para vocês entenderem. Então, todo proxy, uma coisa que a gente tem que lembrar é que ele tem essa questão da composição recursiva. Então, por exemplo, no caso o meu CacheProxy ele implementa a classe, a interface DAO e ele é composto por dos atributos dele vai ser justamente uma instância de DAO, que é quem ele está encapsulando. Eu posso até passar DAO que já está encapsulado por outro proxy, mas ele não precisa ficar sabendo disso. Ele sabe que ele tem cara da abstração ali, certo? Então, no caso ali, ele guarda mapa que tem integer ali que seria ali o meu, o ID, digamos assim, do objeto e ele tem ali o identificado ali que seria digamos assim uma interface que as minhas classes para poderem usar essa estrutura precisariam ter. Basicamente, eu peço que esse Identificado tenha get(id) para eu poder saber quem ele é e poder indexar, digamos assim, esses resultados. Então eu tenho ali no meu construtor, o que é mais importante é eu passar para ele essa classe que eu quero encapsular. Então note que, quando eu crio o meu CacheProxy, eu tenho que passar o DAO para ele como parâmetro. Bom, se eu olhar ali o método recuperar, o que que ele vai fazer? Ele primeiro vai verificar se tem o objeto no cache naquele mapa. Se ele não tiver, ele vai e recupera. Mas note que, se ele não tiver, ele recupera, coloca no cache e retorna. Assim, numa segunda chamada, ele já não vai precisar chamar o método no objeto original novamente. Note por exemplo no método excluir e gravar, quando ele exclui, ele vai lá, ele chama o excluir no objeto original, mas aproveita para excluir lá do cache também. A mesma coisa no gravar. Ele manda gravar no objeto original e aproveita e coloca no cache também. Dessa forma ele mantém a consistência e consegue gravar aí. Note como eu conseguiria por exemplo adicionar isso daí na frente do DAO e adicionar essa funcionalidade sem ter que modificar a minha classe principal. Certo? Vamos ver então outro exemplo de proxy, por exemplo executar operações de forma assíncrona. Muitas vezes por exemplo eu tenho ações que são executadas e tal e aí eu quero que algumas por exemplo executem numa thread separada. A gente chama isso daí de execução assíncrona, ou seja, ao invés de eu chamar método e esperar ele executar para poder continuar fazendo o que eu estou fazendo, eu chamo o método que, enquanto ele executa, eu posso continuar fazendo uma outra coisa para cá. Então às vezes por exemplo eu tenho processamentos muito demorados ou processamentos que de repente eram difícil ter uma resposta, eu só preciso indicar que são interessantes rodarem paralelo com quem está chamando. Então imagina você ter que colocar isso várias classes. O que eu posso fazer é criar proxy que, quando eu chamar, ele vai executar o cara que ele está encapsulando numa thread diferente. Vamos ver como é que seria isso daí. Então, eu vou sair aqui da frente para vocês poderem ver melhor. Eu teria então uma interface ali Transação, eu posso ter algumas outras classes ali, como por exemplo FinalizarOrdem, RemoverItem, ProcessarItem e aí eu tenho por exemplo uma classe ali chamada Execução Assincrona. O que que ele faz? Ele é proxy que eu posso adicionar qualquer uma das outras classes só que, quando eu fizer isso e eu chamar o método executar, ele vai fazer isso numa thread diferente, ele vai fazer isso paralelo. Bom, agora que entrou o código, eu vou voltar aqui. Então, esse código seria exemplo de como seria o código desse Execução Assincrona. Se eu olhar ali cima, é aquela mesma coisinha que eu tenho qualquer proxy, eu tenho atributo com a classe que ele está encapsulando, que é a mesma interface aqui que ele está implementando, e aí eu recebo esse objeto que ele vai encapsular no construtor. Depois aqui eu tenho o método executar. O que que ele vai fazer? Ele está criando ali novo Runnable, que seria ali a classe que, uma classe anônima para executar o método na transação que ele está encapsulando e daí ele cria uma nova thread com esse Runnable que inicia essa thread. Então a gente vê aí que a gente não precisaria por exemplo cada uma das classes que apareceram aqui, eu não precisaria, cada uma dessas classes, ter por exemplo uma lógica de processamento assíncrono, eu poderia ou nem preciso colocar aqui uma interface por exemplo. Eu posso simplesmente ter proxy que eu coloco isso quando eu achar adequado e aí eu não preciso me preocupar colocar todos os casos. Como a gente viu aqui, a gente encapsula o objeto e o chama numa thread diferente. Bom, o tente outra vez aí não é? Tente outra vez! Então não diga que o código está perdido, tenha fé nos padrões. O TenteOutraVez é uma funcionalidade que eu pessoalmente já precisei implementar. às vezes, por exemplo, você tem método que tenta fazer acesso na rede ou tenta fazer algumas coisas que podem estar bloqueadas e, antes de você jogar esse erro para o usuário, você quer tentar algumas vezes fazer aquele acesso. Vamos ver como é que seria o código disso daí. A gente teria por exemplo uma interface ali por exemplo para fazer acesso remoto, imagine ali que por exemplo eu vá pegar arquivo. Eu tenho ali uma classe AcessoServidor que efetivamente tem essa funcionalidade. Se eu precisar por exemplo tentar várias vezes eu teria uma classe que eu chamei de TenteOutraVez para ele chamar o método, se ele jogar uma exceção, ele vai tentando até número x de vezes que eu passar para ele. Vamos dar uma olhada no código? Eu vou sair fora aqui para vocês poderem ver melhor. Então, a gente tem ali, na parte de cima, aquela mesma estrutura, a gente tem ali a classe TenteOutraVez implementando o acesso remoto e a gente tem objeto do tipo AcessoRemoto sendo encapsulado e recebido no construtor. No caso ali a gente também recebe parâmetro inteiro com a quantidade de erros máxima que a gente vai estar tentando outra vez. Depois, se a gente olhar esse método pegarArquivo aqui, olha o que que ele faz, ele cria ali uma variável para a quantidade de tentativas, guarda ali o último erro e aí ele tenta ali: enquanto a quantidade de tentativas for menor que a quantidade de erros, ele vai chamar o método no objeto que ele está encapsulando. Note que ele chama ali o pegarArquivo, se der uma exceção, ele guarda naquela variável o último erro e incrementa o número de tentativas. Então ele vai tentando ali. Se ele conseguir, ele retorna. Se ele der o número ali de erros, ele vai pegar a última exceção que aconteceu e vai lançar. Olha que interessante, como é que a gente consegue por exemplo adicionar uma funcionalidade dessa aí a partir de proxy. Bom, eu acho proxy uma coisa fantástica e realmente a gente só dá valor quando a gente vê alguns bons exemplos de utilização. Nesta aula eu tentei pegar exemplos diferentes aí do cache, de você executar uma classe numa thread diferente, de você por exemplo tentar fazer mecanismo ali de robustez de tentativa para executar o método várias vezes, principalmente métodos remotos. Então a gente vê como pode ser útil ali proxy. Por exemplo esse TenteOutraVez eu poderia de repente estar aplicando a diferentes classes. Então realmente o proxy, ele é mecanismo muito interessante de a gente adicionar funcionalidades no sistema sem ter que modificar as classes que já estão ali. Certo? Então muito obrigado! Continue assistindo o nosso curso! [MÚSICA] [MÚSICA]