Design Patterns: conheça os padrões Observer e PubSub e suas diferenças

Rafael Chinaglia
TOTVS Developers
Published in
5 min readJun 14, 2024

Artigo escrito por Vitor Norton e publicado em iMasters

Enquanto desenvolvemos aplicações que ficam cada mais complexas, os padrões de design desempenham um papel crucial na sua criação. Dois desses padrões, frequentemente utilizados, são os padrões de Design Patterns: Observer e o PubSub. Esses padrões facilitam a comunicação entre objetos em um sistema de uma maneira que estimula o acoplamento flexível e amplia a capacidade de expansão.

Design Patterns

Este artigo, aprofunda-se em apresentar esses padrões e em uma comparação detalhada desses dois padrões, seus casos de uso no mundo real e como eles podem ser implementados com JavaScript.

Design Patterns: — Observer pattern

O padrão Observer é fácil de entender e amplamente utilizado, onde um objeto, chamado sujeito, mantém uma lista de seus dependentes, chamados observadores, e os notifica automaticamente de quaisquer mudanças de estado.

Cenário real

Considere um Cliente e uma Loja. O cliente quer um novo modelo de iPhone que ainda não está disponível na loja. O cliente poderia verificar diariamente, mas a maioria das viagens seria desnecessária.

Alternativamente, a loja poderia enviar spam para todos os clientes sempre que um novo produto chega, poupando alguns de viagens desnecessárias, mas incomodando outros. Isso cria um dilema: ou o cliente perde tempo ou a loja desperdiça recursos.

A solução do padrão observador

No exemplo acima, o Cliente é o observador, enquanto a Loja é o provedor. O Cliente pode querer receber atualizações sobre uma categoria específica de produtos, ou não, dando-lhe a possibilidade de escolher o que quer observar.

Nesse caso, a Loja sabe quem está interessado em suas atualizações. Vários Clientes podem se inscrever para receber atualizações da mesma Loja, e todos receberão notificações sempre que um novo produto for adicionado.

Essa comunicação pode ocorrer toda vez que um novo produto é criado, atualizado ou removido na Loja.

Embora a Loja saiba quem são seus Clientes no Observer Design, ela não se preocupa nem sabe o que cada Cliente fará com as atualizações recebidas. Cada Cliente tem controle total sobre o que fazer com as atualizações que recebe.

Exemplo de código

Se você é como eu, ver o código torna mais simples entender, então aqui está um exemplo simples de código JavaScript ilustrando o padrão Observer:

class Store {
constructor() {
this.observers = [];
}
  add(observer) {
this.observers.push(observer);
}
notify(product) {
this.observers.forEach(observer => observer.update(product));
}
}
class Customer {
update(product) {
console.log(`New product added: ${product}`);
}
}
const store = new Store();
const customer = new Customer();
store.add(customer);
store.notify('iPhone 15');

No código acima, temos a criação de duas classes, Store e Customer.

A classe Store representa o provedor (algumas pessoas podem chamá-lo de subject). Ela tem um array observers que armazena todos os observadores (instâncias de Customer) que estão interessados em atualizações da Store. Também possui um método add para adicionar um novo observador e um método notify para notificar todos os observadores sobre um novo produto.

Enquanto a classe Customer representa o observador, ela tem um método update que faz alguma ação quando recebe a atualização, neste caso, ela faz um log no console.

Tudo pronto, vamos implementar isso. Então criamos um objeto Store e Customer. O Customer é adicionado aos observadores da Store usando o método add.

Então, a Store notifica todos os seus observadores (neste caso, apenas um Customer) sobre um novo produto ('iPhone 15') usando o método notify. O método customer.update() é chamado, e ele registra o novo produto no console.

Design Patterns: Padrão de Design Pub Sub

O Padrão PubSub é um padrão de mensagens que promove o pouco acoplamento e alta escalabilidade. Este padrão é centrado na ideia de enviar mensagens de publicadores para um número não especificado de assinantes, ou ouvintes, promovendo assim uma dependência de muitos para muitos entre objetos.

Cenário real

Vamos pensar em uma aplicação de grupo de chat, o sistema Pub/Sub pode ser usado para lidar com o envio e recebimento de mensagens:

Assinando um evento

Quando uma janela de chat é aberta, ela se inscreve em um evento, digamos o newMessage.

Isso é feito usando pubsub.subscribe("newMessage", callback). A função de callback é o que será executado quando uma nova mensagem for publicada para o evento newMessage. Nesse caso, o callback registra a nova mensagem e atualiza a interface do chat.

const messageData = { user: "Usuário A", text: "Isso é o que o usuário digitou" };
pubsub.publish("newMessage", messageData);

Dessa forma, o sistema Pub/Sub permite o desacoplamento das janelas de chat (assinantes) e dos remetentes de mensagens (publicadores). As janelas de chat não precisam saber quem envia mensagens, elas só precisam saber o que fazer quando uma mensagem é recebida.

Da mesma forma, os remetentes de mensagens não precisam saber quem receberá as mensagens, eles só precisam enviar mensagens para o tópico certo.

PubSub com o Real-time Data Engine

Esta é uma parte importante da arquitetura de um desenvolvimento de software e, no entanto, na maioria dos casos, não é o core do negócio do que você está construindo. Criar um sistema PubSub confiável e escalável que sincroniza dados entre diferentes instâncias da nossa aplicação pode ser desafiador.

Estamos em 2024, o que significa que já existe uma solução para isso: o Real-time Data Engine da SuperViz, por exemplo. A SuperViz oferece um SDK e uma API de colaboração e comunicação em tempo real, projetados para desenvolvedores que estão construindo aplicativos web em tempo real.

Usando o SuperViz, você pode criar uma sala com vários participantes que, ao publicar um evento, ele será transmitido para todos os participantes da sala que estão acessando através de diferentes dispositivos e redes. Isso significa que quaisquer atualizações feitas por um participante serão refletidas em tempo real em todos os dispositivos, proporcionando uma experiência perfeita e colaborativa.

SuperViz fornece a infraestrutura necessária para construir aplicações realtime. Isso inclui a capacidade de também capturar esses eventos em seu backend usando webhooks, e também de publicar um evento com uma simples solicitação HTTP, para citar alguns recursos.

Design Patterns: Principal diferença

Ambos os padrões têm um conceito de publicar algo e se inscrever em um observador, certo? Então qual é a diferença?

O padrão Observer resolve isso permitindo que o Cliente se anexe como um Observador à Loja. Quando o iPhone chega, a loja notifica todos os Observadores anexados. Enquanto na aplicação PubSub, a aplicação publica um evento e seus dados para um event broker, e então os inscritos ouvem este event broker. O publicador não tem conhecimento dos seus observadores.

No nosso cenário Cliente-Loja, o event broker da aplicação PubSub poderia ser como um marketplace. Ele precisaria manter o controle da disponibilidade de produtos na loja. Quando um novo iPhone chega, o sistema registraria este evento e notificaria todos os inscritos (clientes que expressaram interesse no iPhone) enviando-lhes um e-mail ou uma notificação push.

--

--

Rafael Chinaglia
TOTVS Developers

Jornalista/ Editor do iMasters, Gestor de projetos e produtor de conteúdo para TOTVS Developers.