Skip to content

Latest commit

 

History

History
155 lines (120 loc) · 5.09 KB

File metadata and controls

155 lines (120 loc) · 5.09 KB

Observer

O que é?

O Observer é um padrão comportamental que define uma dependência um-para-muitos entre objetos, de modo que quando um objeto muda de estado, todos os seus dependentes são notificados e atualizados automaticamente.

Quando usar?

  • Quando mudanças no estado de um objeto precisam ser refletidas em outros objetos
  • Quando um objeto precisa notificar outros objetos sem fazer suposições sobre quem são esses objetos
  • Quando você precisa de um acoplamento fraco entre objetos que interagem
  • Quando você tem uma estrutura de publicação/assinatura

Exemplo em Python

from abc import ABC, abstractmethod
from typing import List, Set

# Interface do Observer
class Observer(ABC):
    @abstractmethod
    def atualizar(self, temperatura: float, umidade: float, pressao: float) -> None:
        pass

# Interface do Subject
class Subject(ABC):
    @abstractmethod
    def anexar(self, observer: Observer) -> None:
        pass

    @abstractmethod
    def desanexar(self, observer: Observer) -> None:
        pass

    @abstractmethod
    def notificar(self) -> None:
        pass

# Subject Concreto
class EstacaoMeteorologica(Subject):
    def __init__(self):
        self._observers: Set[Observer] = set()
        self._temperatura = 0.0
        self._umidade = 0.0
        self._pressao = 0.0

    def anexar(self, observer: Observer) -> None:
        self._observers.add(observer)

    def desanexar(self, observer: Observer) -> None:
        self._observers.remove(observer)

    def notificar(self) -> None:
        for observer in self._observers:
            observer.atualizar(self._temperatura, self._umidade, self._pressao)

    def set_medicoes(self, temperatura: float, umidade: float, pressao: float) -> None:
        self._temperatura = temperatura
        self._umidade = umidade
        self._pressao = pressao
        self.notificar()

# Observers Concretos
class DisplayAtual(Observer):
    def atualizar(self, temperatura: float, umidade: float, pressao: float) -> None:
        print(f"\nDisplay Atual:")
        print(f"Temperatura: {temperatura}°C")
        print(f"Umidade: {umidade}%")
        print(f"Pressão: {pressao}hPa")

class DisplayEstatistico(Observer):
    def __init__(self):
        self._temperaturas: List[float] = []
        self._umidades: List[float] = []
        self._pressoes: List[float] = []

    def atualizar(self, temperatura: float, umidade: float, pressao: float) -> None:
        self._temperaturas.append(temperatura)
        self._umidades.append(umidade)
        self._pressoes.append(pressao)

        print(f"\nDisplay Estatístico:")
        print(f"Temperatura Média: {sum(self._temperaturas) / len(self._temperaturas):.1f}°C")
        print(f"Umidade Média: {sum(self._umidades) / len(self._umidades):.1f}%")
        print(f"Pressão Média: {sum(self._pressoes) / len(self._pressoes):.1f}hPa")

class DisplayPrevisao(Observer):
    def __init__(self):
        self._ultima_pressao = 0.0

    def atualizar(self, temperatura: float, umidade: float, pressao: float) -> None:
        print(f"\nDisplay Previsão:")
        if pressao > self._ultima_pressao:
            print("Melhorando o tempo!")
        elif pressao < self._ultima_pressao:
            print("Possibilidade de chuva!")
        else:
            print("Tempo estável")
        self._ultima_pressao = pressao

def main():
    # Criando a estação meteorológica
    estacao = EstacaoMeteorologica()

    # Criando os displays
    display_atual = DisplayAtual()
    display_estatistico = DisplayEstatistico()
    display_previsao = DisplayPrevisao()

    # Registrando os displays como observers
    estacao.anexar(display_atual)
    estacao.anexar(display_estatistico)
    estacao.anexar(display_previsao)

    # Simulando mudanças nas medições
    print("Primeira medição:")
    estacao.set_medicoes(25.0, 65.0, 1013.0)

    print("\nSegunda medição:")
    estacao.set_medicoes(26.0, 70.0, 1014.0)

    # Removendo um display
    print("\nRemovendo display estatístico...")
    estacao.desanexar(display_estatistico)

    print("\nTerceira medição:")
    estacao.set_medicoes(24.0, 75.0, 1012.0)

if __name__ == "__main__":
    main()

Vantagens

  1. Estabelece relações entre objetos em tempo de execução
  2. Promove o baixo acoplamento entre objetos
  3. Suporta o princípio Aberto/Fechado
  4. Permite enviar dados para vários objetos de uma só vez
  5. Facilita a manutenção e extensão do código

Desvantagens

  1. Os observers podem ser notificados em ordem aleatória
  2. Se não implementado corretamente, pode levar a problemas de desempenho
  3. Pode causar vazamentos de memória se os observers não forem desanexados corretamente
  4. Pode ser difícil rastrear mudanças em sistemas complexos

Considerações de Implementação

  • Considere usar uma estrutura de dados apropriada para armazenar os observers
  • Implemente mecanismos de desanexar observers para evitar vazamentos de memória
  • Considere usar variantes do padrão como Push vs Pull
  • Pense em como lidar com exceções durante as notificações
  • Em sistemas distribuídos, considere a possibilidade de notificações assíncronas