Behavioral Behavioral Patterns Patterns –– Observer Observer Criar uma relação de dependência do tipo um-para-muitos, de tal forma que o lado “muitos” seja notificado quando de uma mudança do lado “um”. Objetivo é evitar acoplamento forte para o relacionamento entre classes. O lado que notifica alterações não necessita limitar o número de “notificados” 4-jun-09 Leandro Tonietto 230 Behavioral Behavioral Patterns Patterns –– Observer Observer Exemplo em [1]: Aplicação de planilha eletrônica. A aplicação deve manter a visualização gráfica dos dados coerente com o estado atual dos mesmos. Os gráficos compartilham os mesmos dados para exibição, mas possuem implementação distinta. Quando o usuário modifica um valor de uma célula que contem algum dado do gráfico, todos os gráficos associados com este dado devem ser atualizados para manter a coerência da visualização. A solução é implementar um objeto (subject) que possa cuidar dos dados da planilha e notificar aos gráficos associados (observers) que o dado foi alterado. 4-jun-09 Leandro Tonietto 231 Behavioral Behavioral Patterns Patterns –– Observer Observer Exemplo em [1]: 4-jun-09 Leandro Tonietto 232 Behavioral Behavioral Patterns Patterns –– Observer Observer Estrutura básica: 4-jun-09 Leandro Tonietto 233 Behavioral Behavioral Patterns Patterns –– Observer Observer Estrutura básica: 4-jun-09 Leandro Tonietto 234 Behavioral Behavioral Patterns Patterns –– Observer Observer Aplicação: Quando objetos de dependência em certos aspectos da aplicação, tendo que se manter coerentes um ao outro, porém deve ser possível evoluí-los de forma independente. Quanto observers devem ser mudados por algum estado especial de um subject. Inclusive não possível saber qual será o tipo concreto de observador, nem a quantidade de observadores (não deve haver acoplamento forte entre as partes) 4-jun-09 Leandro Tonietto 235 Behavioral Behavioral Patterns Patterns –– Observer Observer Conseqüências: Permite o reuso independente de subjects e observers. Acoplamento com classes abstratas para subject e para observer. Um lado não precisa saber das implementações concretas do outro. O subject apenas notifica observadores, o que estes fazem com a notificação é de responsabilidade dos próprios observadores. Como o subject possui uma coleção de observer, é permitido fazer comunicação broadcast entre os objetos. Subject não necessita saber quantos observadores ele tem, ele apenas propaga a notificação. Atualizações inesperadas por causa da dependência “cega”. Como a notificação é geral, os dados sobre ela também são, então há o custo de detecção das mudanças. Uma solução é fazer mais de um método notificador no subject, um para cada tipo de notificação. Isto auxilia o observador a considerar ou descartar notificações. Outro problema é observadores podem ficar longo tempo para serem notificados por conta das ações que algum outro desencadeou. 4-jun-09 Leandro Tonietto 236 Behavioral Behavioral Patterns Patterns –– Observer Observer Implementação: Mapear os observers nos subjects. Subjects possuem uma coleção de observers, que serão notificados. É possível utilizar uma estrutura tipo hashtable para fazer o mapeamento subject-observer. Tem maior custo de acesso aos observadores. Um observer pode esperar pela notificação de mais de um subject ao mesmo tempo. Neste caso, na operação de update, pode-se passar um ponteiro para o próprio subject que está gerando a notificação. Colocar a notificação no subject x controlar pelo client. Melhor no subject, mas deve-se tomar o cuidado de manter a sincronização das notificações e da atualização dos estados dos subjects. 4-jun-09 Leandro Tonietto 237 Behavioral Behavioral Patterns Patterns –– Observer Observer Implementação: Deleção do subject pode notificar o observer para manter a integridade das referências. Deleção do observer deve prever a desvinculação com o subject. Operação removeObserver() no subject. Cuidar para atualizar estado do subject antes da notificação. Notificação parametrizada X sem parâmetro Na parametrizada, as mudanças são informadas na notificação. Pode enviar mudanças desnecessárias. Sem parâmetros na notificação, os observadores devem buscar as mudanças de interesse diretamente do subject. Não envia mudanças desnecessárias, porém implica em buscar cada mudança em separado. 4-jun-09 Leandro Tonietto 238 Behavioral Behavioral Patterns Patterns –– Observer Observer Implementação: Listas de observadores diferentes para notificações diferentes. Evita chamadas desnecessárias aos observadores que interessados em mudanças ou eventos específicos. Uso de um objeto gerenciador de mudanças / notificações pode ser interessante. Por exemplo, caso um observador deve esperar pela notificação em seqüência de diversos subjects. O objeto gerenciador pode controlar as notificações e notificar o observador apenas no fim. 4-jun-09 Leandro Tonietto 239 Behavioral Behavioral Patterns Patterns –– Observer Observer Exemplo: Classe que implementa um Timer. O objeto timer pode ser usado para contabilizar e notificar o tempo de processamento de uma determinada operação. Também um componente gráfico pode exibir que implementa um cronometro, fazendo uso de um objeto Timer. A cada clock (1 segundo) do Timer, o componente gráfico do cronômetro recupera do timer qual é o tempo atual e desenha de maneira formatada na interface. Ainda, é possível mostrar uma formatação diferenciada para o cronômetro quando o foi solicitado a parada do timer. 4-jun-09 Leandro Tonietto 240 Behavioral Behavioral Patterns Patterns –– Observer Observer Exemplo: 4-jun-09 Leandro Tonietto 241 Behavioral Behavioral Patterns Patterns –– Observer Observer Exercício: Considere um carregador de arquivo de nível de jogo. O jogo deve carregar as informações de um nível apenas no início do mesmo. Suponha que o arquivo que contenha muitas informações e que demora muito tempo para carregá-lo. Afim de não deixar o usuário sem um feedback sobre o que está acontecendo durante a carga, o projetista do jogo previu uma caixa de diálogo com uma barra de progresso da carga do nível. A barra é atualizada a cada etapa lida do arquivo (a cada objeto ou a cada n-bytes). Para tanto, o carregador de nível deve informar á quantidade dados lidos, ou a última etapa lida ou ainda, o percentual lido arquivo. Faça o diagrama de classes para resolver esta situação usando o pattern Observer. 4-jun-09 Leandro Tonietto 242 Behavioral Behavioral Patterns Patterns –– Observer Observer Exercício: 4-jun-09 Leandro Tonietto 243