Vamos falar então sobre o padrão Observer. O Observer é padrão de projeto que cai na categoria comportamental. O objetivo dele é definir uma dependência de para muitos, entre objetos, de forma que quando o estado de objeto muda, os dependentes desse estado são notificados e atualizados automaticamente. Ele provê uma ligação de baixo acoplamento entre o objeto central, que é esse sujeito observável, e uma série, ou mais observadores que ficam observando este objeto, esse sujeito, interessados mudanças relevantes no seu estado. Qual é que é o funcionamento dele? Quando o estado do sujeito observado muda ele notifica todos os seus observadores, mas essa notificação é feita de uma forma flexível e implícita, como a gente vai ver. Quando recebem a notificação os observadores podem decidir que ações eles vão tomar baseado no tipo de modificação que eles foram notificados. Exemplos de uso desse padrão. Por exemplo, se você quer fazer acompanhamento da furação de uma eleição eletrônica. Você pode ter diferentes observadores interessados naquela eleição. Você pode ter observador que é sistema que vai gerar alguns gráficos de barras, ou gráficos de torta, mostrando a proporção de votos que cada candidato teve. Ou você pode ter outro observador interessado a cada 1000 votos, ele está interessado ser notificado e ele faz relatório da eleição a cada 1000 votos. Você pode ter terceiro observador que está interessado quando muda, quando candidato passa na frente de outro candidato. Ele é notificado disso daí ele vai, por exemplo, disparar uma mensagem de Whatsapp quando isso acontece. Então você pode ter diferentes observadores todos eles interessados na mesma coisa, que é a apuração daquela eleição. Outro exemplo, acompanhamento de jogo de futebol. Você pode querer por exemplo ter tipo de usuários que está interessado saber apenas quando acontece gol, então toda a vez que tem gol ele quer receber essa notificação. Ou você pode ter usuário que está interessado ter como se fosse painel ali que vai mostrando várias informações sobre o jogo, todas as jogadas. Você pode ter terceiro observador, técnico por exemplo, interessado detalhes estatísticos como a passe de bola de cada jogador, o número de passes certos e errados, então você quer saber maior detalhamento. Todos esses querem receber informações quando muda o estado daquele jogo. Leilão eletrônico por exemplo, você pode ter várias pessoas participando do leilão e algumas pessoas assistindo no leilão e todas elas querem ser notificadas quando muda o lance ali, o maior lance até então naquele leilão, ou quer ser notificado quando o objeto que está leilão é vendido, ou coisa do gênero. Pense você também num exemplo, num caso que você tem uma parte do sistema que pode ser representada por objeto que tem várias outras partes do sistema observando aquilo e elas têm interesse mudanças no estado porque cada vai fazer algo pouco diferente aí, de acordo com a mudança no estado que ocorreu. Esse é o caso que a gente vai querer usar o padrão Observer. Como que é o diagrama da arquitetura do padrão? Então a gente tem o sujeito aqui, que é o objeto cujo estado a gente está interessado observar, e esse sujeito vai ter uma coleção de observadores aqui. Esse observador, você pode ter uma interface abstrata aqui, com método update e daí vários tipos diferentes de observadores concretos aqui que você implementa. E o que o sujeito faz? Ele mantém essa lista de observadores. Você tem método para registrar novo observador e método para desregistrar observador. E daí algum momento quando muda o estado desse sujeito ele chama esse método notifyObservers. Que é que faz o notifyObservers? Aqui, para cada observador na coleção de observadores, ele chama o método update nesse Observer. Então chama esse método update e daí cada observador vai decidir o que fazer quando recebe esse update, ele pode fazer diferentes coisas. Então essa é a estrutura básica. Deixa eu mostrar exemplo de como a gente poderia implementar isso na linguagem Python e eu vou mostrar de uma forma bem pythônica. Essa palavra pythônica, inglês é pythonic, português a gente inventa aí pythônica, quer dizer que a gente está usando bem o estilo de programação de Python para fazer essa codificação. Eu vou abrir aqui o Spyder, que é editor de textos Python que eu gosto de utilizar, e a gente vai ver como é que funciona isto aqui. Então essa aqui é uma demonstração que foi escrita pelo Evan Dempsey de Dublin e eu e o Guilherme Feulo fizemos algumas modificações aqui. Então a gente tem a classe subject, que é uma subclasse de object, está aqui, esta classe subject é quem vai representar o nosso objeto central do nosso padrão. Quando você for implementar esse padrão num sistema, provavelmente o nome dela não vai ser subject, vai ser o nome do papel dessa classe naquele sistema que você está implementando. Então é a classe sujeito, subject, e daí a gente define primeiro o construtor, Python o construtor é escrito dessa forma sublinhado sublinhado init sublinhado, sublinhado. E que é que a gente faz nesse construtor? A gente cria dois dicionários. Ou melhor, desculpa, a gente define duas propriedades e a gente adiciona essas propriedades no no dicionário de propriedades do objeto. A primeira propriedade a gente chama de estado, num caso específico você diria exatamente tipo o nome da variável que você está interessado, aqui é uma coisa genérica então eu simplesmente chamei de estado. Inicializei com zero e depois você teria aqui conjunto de observadores, que eu inicializei como conjunto vazio. Então são os observadores aqui que a gente vai notificar quando o nosso estado muda. Daí a gente vai usar, isso aqui é uma coisa bem pythônica, esse setattr. Setattr é método de Python que é método que é chamado toda a vez que alguém altera o valor de atributo desse meu objeto. Então é uma espécie de reflexão computacional que ele usa aqui, uma interposição desse método, que toda a vez que eu mudo o valor de atributo ele chama esse método, onde name vai ser o nome do atributo que eu estou mudando e value vai ser o valor que eu estou colocando naquele atributo. Então o usuário, o cliente, o código do cliente, não vai chamar explicitamente o método do setattr. Ele simplesmente vai fazer uma atribuição, olha vai fazer por exemplo x recebe zero. Só que o x recebe zero se eu definir esse setattr, vai gera uma chamada nesse método onde name vai ser x e value vai ser zero. Então o que é que a gente faz na implementação desse setattr? A primeira coisa a gente realmente faz a atribuição, então eu faço isso aqui: esse é o dicionário de atributos, na posição name, que é o nome da variável, coloco o valor que o usuário quis colocar, então esse aqui é a atribuição si, e depois eu verifico. Se o nome desse meu atributo, dessa minha propriedade, é state, " o state é isso que eu quero notificar os meus observadores", daí o que é que eu faço? Eu chamo o método notifyObservers. Então toda a vez que alguém mudar o valor dessa variável state, ele vai chamar o método notifyObservers. Que é que faz o método notifyObservers? Ele faz isso aqui: para todos os observadores no meu conjunto de observadores você chama o método server.update. E depois tem esses dois métodos, é método para registrar novos observadores, que eu acrescento aqui nessa minha lista de observadores, no meu conjunto de observadores, e o deregister que é para remover alguém desse meu conjunto de observadores, ok? E daí eu tenho uma classe Observer. Primeiro eu tenho o Observer abstrato e depois eu crio três aí subclasses concretas. Então esse observer abstrato simplesmente eu estou definindo aqui que eu vou ter método chamado update e caso alguém chame esse método update nessa classe abstrata eu simplesmente gero essa excepção para mostrar que não deve se chamar isso na classe abstrata, você deve chamar nas classes concretas. E daí sim vêm as minhas três classes concretas aqui. Primeira é BinaryObserver. Que é que esse BinaryObserver faz? Então aqui no construtor, primeiro o construtor recebe como parâmetro o subject, que é quem que ele está observando, é o sujeito que ele está observando. Eu guardo esse subject nesse meu atributo local chamado subject e eu chamo o método register do meu sujeito, então eu chamo o método do registry no sujeito, passando o que como parâmetro? Eu mesmo, self. Porquê? Porque eu Quero ser observador daquele sujeito, então "self" quero ser observador daquele sujeito. Então, esse aqui é o construtor. E depois tem o método update. Qual é a implementação do update? É muito simples, ele simplesmente, ele vai imprimir binário aquele número que é o estado do sujeito. Como que ele faz isso? Ele usa o comando "print" aqui do Pyton. Primeiro ele imprime "tab", depois o texto binário, e depois ele chama aqui o valor "self.subjetc.state", esse vai recuperar o estado dessa variável "state" e vai converter para binário e daí ele imprime isso aqui. Então, simplesmente toda vez que mudar o valor da variável "state" no sujeito, ele vai imprimir binário o valor dessa variável. E depois vocês já podem ter imaginado os próximos, né, os outros dois é o "OctalObserver", que ele é idêntico só que ele imprime na base oito, ao invés de ser na base dois, é na base oito ou octal. E depois, finalmente, "HexadecimalObserver" é idêntico também, só que ele imprime hexadecimal o valor. E depois, só para testar, eu tenho aqui uma função main. O que é que faz essa função main? Eu crio o sujeito, depois eu crio os três observadores passando o sujeito como parâmetro, porque são observadores daquele sujeito e depois eu faço o seguinte, olha, mando imprimir primeiro a mudança de estado, daí eu simplesmente faço isso aqui olha: "subject.state" recebe 1024. Simplesmente altero o estado do sujeito e daí, implicitamente, os observadores vão ser notificados. Então, note que aqui não tem nenhuma mensagem dessa comunicação entre observador e sujeito, isso acontece de forma implícita. Depois, aqui, a segunda mudança de estado, eu faço "state" recebe 255. Eu vou executar isso aqui para a gente ver o resultado, só apertar esse botão para executar e pronto. Olha, a gente consegue ver aqui. Então, a primeira mudança de estado hexadecimal, aquele valor lá é 400, binário é isso aqui, o 1024 decimal é isso aqui binário e octal é 2000. Já o segundo valor que eu tinha colocado aqui é 255, hexadecimal é ff, binário é esse monte de 1 aqui, oito 1, e octal é 377, tá? Então, veja que interessante, o código aqui, ele simplesmente tá mexendo nos atributos, mas esse mecanismo de comunicação implícita do observer entra ação e faz tudo isso aqui acontecer. Bem interessante, não é? Continuando aqui, outra coisa bem interessante é que na linguagem smalltalk, os métodos do observer e do subject fazem parte da classe object. Então, na verdade, o observer é parte fundamental da linguagem smalltalk, porque lá todo objeto da linguagem já vem com o código pronto para ser observador e para ser o sujeito do padrão observer. Então, o observer é usado muito naquela linguagem. Outras variações que a gente pode ter nesse padrão, a notificação. A notificação pode, opcionalmente, incluir já o que mudou. Então, por exemplo, se você muda o estado, você já diz o que mudou. Então, vamos supor que você tenha o sistema de controle de elevador, e daí o elevador, ele pode mudar tanto a temperatura lá dentro, você tem o sensor de temperatura, quanto o andar que ele está a medida que ele se movimenta. Então, você pode, a medida que o elevador se movimenta, você já manda a notificação pelo número do andar e você já diz o novo andar que ele mudou. Essa é uma opção que você já inclui o que mudou. Outra opção é você simplesmente, olha, mudou o meu estado, daí o observador, ele que toma a iniciativa de pegar o estado novo se ele tiver interesse, porque daí ele só pode pegar a parte do estado que ele tenha interesse, não precisa enviar o estado inteiro. Outra dimensão que a gente tem aqui é se o tipo de notificação é o tipo único, ou seja, você simplesmente diz que mudou e deixa o observador se virar para saber o que mudou ou você pode, o smalltalk, por exemplo, tem essa opção de você dizer o que mudou e daí então, por exemplo, o elevador pode falar: "mudou a temperatura"; ou ele pode falar: "mudou o andar que eu estou"; e daí o observador, pode ter observadores diferentes para cada tipo de mudança ou o observador, se ele não tá interessado naquele tipo de mudança, ele ignora. Então, tem essas várias possibilidades diferentes aqui do padrão observer. O padrão observer também é conhecido como publish/subscribe. Você tem o sujeito publica coisas e os observers que assinam, manifestam interesse nessa publicação, pode ser event-subscriber também, listener, você tem observadores ouvindo ali o que tá acontecendo com o sujeito e eu gosto bastante também que ele implementa chamadas de método implícitas. Lembra que quando a gente simplesmente fez atribuição daquele valor, uma série de chamadas de métodos aconteceram, as chamadas de método do sujeito para os observadores são implícitas. Isso é uma coisa que dá poder para você muito grande, porque ele fornece acoplamento abstrato entre observados e observadores. O sujeito não sabe nada sobre os seus observadores, aquilo tá implícito ali embaixo. Você tem que tomar cuidado, porque se há muitas pequenas atualizações do sujeito, o desempenho pode se degradas rapidamente. Uma coisa interessante, ele segue aquele princípio open/close, aberto/fechado, do solid. Porque você pode acrescentar novos observadores sem mudar o sujeito e vice-versa. Finalmente, é possível estabelecer relações entre objetos tempo de execução, você pode acrescentar observadores tempo de execução ou remover, alterar os observadores tempo de execução. Então, essa dependência dos objetos é algo muito dinâmica se você usa esse padrão. E observadores são notificados numa ordem inespecificada. Então, se você precisa que os observadores sejam avisados numa ordem específica, aqui não vai funcionar, porque aqui a ordem é meio indeterminada quem que vai ser avisado antes ou depois. Então, resumindo, é isso, o observer é padrão comportamental que permite que você defina mecanismo de manifestação de interesse, que é chamado de subscription, ou assinatura, sujeito observado, e quando o estado desse sujeito muda, todos os observadores que manifestaram interesse são notificados. E ele permite essa comunicação super-flexível, dinâmica e com baixo acomplamento entre sujeito e observadores. Então, se você quiser aprender mais sobre o padrão observer, eu sugiro você ler lá no GoF o livro de Design Patterns. Outro livro que eu já falei aqui, o Head First Design Patterns, é bastante interessante e tem alguns websites. Por exemplo, agora eu escolhi esse refactoring guru, que tem umas inscrições bem interessantes e uns desenhos bem humorados sobre os padrões e você pode dar uma olhada no observer lá, vai ser algo bem interessante. Então é isso, espero que vocês tenham gostado do padrão observer. [SEM_ÁUDIO]