Nos últimos posts sobre o player HLS, usamos a biblioteca EventEmitter3 para enviar e receber eventos. O que talvez você não saiba é que ela implementa o Padrão Observer. Neste artigo, vamos explorar esse padrão, entender como ele funciona e aplicá-lo a um caso real.

O que é o Padrão Observer?

O Padrão Observer se baseia em uma relação de inscrição e notificação, onde um objeto (o “Subject”) notifica outros objetos (“Observers”) sobre mudanças em seu estado. Pense em uma lista de transmissão: você se inscreve, recebe as notificações e pode cancelar a qualquer momento.

Exemplo do padrão observer

Agora, por que isso é relevante? Em aplicações modernas, precisamos reagir a eventos de forma organizada, e o Observer nos ajuda a encapsular essa lógica.

Exemplo prático

Imagine que estamos criando um player de vídeo customizado com uma interface minimalista: uma tag <video> e um botão “Play/Pause”. Sempre que o vídeo inicia ou pausa, queremos atualizar o texto do botão para refletir o estado atual. Veja como isso funciona em um código simples:

const $video = document.querySelector("video");
const $toggle = document.querySelector("button");

$toggle.addEventListener("click", togglePlay);
$video.addEventListener("play", updateButton);
$video.addEventListener("pause", updateButton);

function togglePlay() {
  const method = $video.paused ? "play" : "pause";
  $video[method]();
}

function updateButton() {
  $toggle.textContent = $video.paused ? "Play" : "Pause";
}

Essa implementação funciona, mas e se quisermos adicionar mais funcionalidades? Por exemplo, enviar métricas ou registrar logs sempre que o estado mudar?

Uma solução inicial seria criar funções específicas para cada caso. Por exemplo:

$video.addEventListener("play", onPlay);
$video.addEventListener("pause", onPause);

function onPlay() {
  updateButton();
  log("Vídeo está tocando");
  sendAnalytics();
}

function onPause() {
  updateButton();
  log("Vídeo foi pausado");
  sendAnalytics();
}

Funciona? Sim. Mas, e se no futuro quisermos adicionar ou remover funcionalidades em tempo de execução? O código rapidamente se torna rígido e difícil de escalar.

Como o Padrão Observer resolve isso?

Com o Observer, podemos abstrair essas ações. O Subject centraliza a lógica e notifica os Observers (ou assinantes) sempre que um evento ocorre. No JavaScript, criamos um objeto que gerencia os Observers:

const subject = {
  observers: [],

  subscribe(func) {
    this.observers.push(func);
  },

  unsubscribe(func) {
    this.observers = this.observers.filter((observer) => observer !== func);
  },

  notify(data) {
    this.observers.forEach((observer) => observer(data));
  },
};

export default subject;

Agora, cada Observer pode se inscrever para receber notificações:

subject.subscribe(updateButton);
subject.subscribe(log);
subject.subscribe(sendAnalytics);

E os eventos no player notificam o Subject:

const $video = document.querySelector("video");

$video.addEventListener("play", () => {
  subject.notify("play");
});

$video.addEventListener("pause", () => {
  subject.notify("pause");
});

Benefícios

  • Escalabilidade: Adicione ou remova funcionalidades sem alterar a lógica principal.
  • Manutenção Simplificada: O código fica mais modular e fácil de entender.
  • Reutilização: Funções como log ou sendAnalytics podem ser reutilizadas em diferentes contextos.

Conclusão

O Padrão Observer não é apenas uma boa prática de desenvolvimento; ele é um passo em direção a um código mais organizado, escalável e sustentável. Experimente o Padrão Observer e veja como ele funciona nos seus projetos!