C# - Padrão Comportamental Gof - Observer
C# - Padrão Comportamental Gof - Observer (revisitado)
Neste artigo vamos recordar o padrão comportamental Gof Observer.
Segundo a definição da Gang Of Four(GoF), o padrão Observer define uma dependência um-para-muitos entre objetos para que, quando um objeto mudar de estado, todos os seus dependentes sejam notificados e atualizados automaticamente.
Este padrão permite que um objeto notifique outros objetos sobre alterações em seu estado.
Neste padrão temos um objeto (chamado de Subject) mantém uma lista de seus dependentes (chamados de Observers) e os notifica automaticamente sempre que algum estado muda, chamando um de seus métodos.
Então o padrão Observer é útil quando precisamos que dois ou mais objetos "escutem" a determinados eventos em um outro objeto.
Dessa forma podemos dizer que o padrão Observer tem dois componentes principais:
São objetos publicadores (publishers) – Quando ocorre alguma mudança no estado de um Subject ele deve notificar todos os seus assinantes (subscribers)
Eles são os assinantes (subscribers). Eles simplesmente ouvem as mudanças dos subjects.
Uma tradução livre para Subject seria Sujeito e para Observer seria Observadores eu vou usar os nomes no idioma inglês.
Observer : Exemplo
Vejamos um exemplo para entender o padrão Observer.
Suponha que temos um Subject (que tem um estado) e alguns Observers:
Neste cenário, os objetos Observers querem ser atualizados quando algo mudar no Subject.
Então para isso a cada 10s eles enviam uma solicitação ao Subject se algo mudou, e, assim o objeto Subject tem que ser conhecido pelos objetos Observers.
Temos aqui que muitos Observers dependem de um Subject (definindo o relacionamento de muitos para um).
Percebemos que o problema aqui é manter os objetos Observers atualizados com relação as mudanças que o objeto Subject publica.
Agora vamos supor que o intervalo entre as mudanças seja de 60 segundos. Neste intervalo cada objeto Observer já realizou 6 solicitações ao objeto Subject sendo que somente a última retornará com uma resposta positiva e as demais foram desnecessárias.
Outro problema aqui é a quantidade de objetos Observers quando mais objetos Observers existirem maior será a quantidade
de solicitações não necessárias. Assim sem usar o padrão Observer os observadores tem que ficar enviando solicitações ao subject em intervalos de tempo o que pode consumir recursos e não ser eficiente.;
Para resolver este problema podemos usar o padrão Observer.
A proposta do padrão Observer é que os objetos Observers devem pedir ao Subject que os notifiquem quando algo mudar.
Assim teremos o objeto Subject e os objetos Observers mas agora o objeto Subject é quem notifica os observers quando houver alguma mudança. E assim agora temos que um Subject depende de muitos Obsevers (dependência um-para-muitos)
Mas para isso funcionar é preciso que haja um acordo entre o Subject e os Observers. Onde os Observers :
- Precisam fornecer um canal para que o Subject os notifiquem.
- Precisam conhecer o Subject que desejam observar
E o Subject :
- Precisa fornecer um canal para que os observers possam se cadastrar como observadores.
- E também um canal para que os Observers possam se descadastrar como observadores.
- Deve ser capaz de notificar todos os observers quando sofrer uma atualização
Para isso o Subject deve manter uma lista dos Observers que se inscreveram para serem notificados das mudanças. E agora sempre que ocorrer alguma mudança no seu estado o Subject envia uma notificação para todos os inscritos na lista. Com isso não existem mais o problema das solicitações desnecessárias.
Com isso o uso do padrão Observer fornece uma forma de reagir a eventos que acontecem em objetos sem ter um forte acoplamento em suas classes.
A ideia fundamental por trás do padrão do observador é centralizar a tarefa de informar dentro do Subject. Portanto, ele mantém uma lista na qual os observadores podem se cadastrar para ingressar. Em caso de alteração, o subject informa os observadores cadastrados - um após o outro - sem que eles próprios tenham que agir.
Se uma atualização automática de status não for mais desejada para um determinado objeto observador, ela pode simplesmente ser removida da lista.
1- Subject -
- Conhece seus Observers;
- Fornece uma interface para anexar e desanexar objetos Observer;
- Qualquer número de objetos Observer pode observar um Subject;
2- ConcreteSubject
- Armazena o estado de interesse para ConcreteObserver;
- Envia uma notificação para seus observadores quando seu estado muda;
3- Observer - Def
- Define uma interface de atualização para objetos que devem ser notificados das mudanças em um Subject;
4- ConcreteObserver - I
- Mantém uma referência a um objeto ConcreteSubject;
-Implementa a interface de atualização do Observer para manter seu estado consistente com o do Subject;
- Armazena o estado que deve permanecer consistente com o do Subject;
- Quando uma modificação do estado de um objeto implica modificações em outros objetos;
- Quando um objeto deve ser capaz de notificar outros objetos, mas sem pressupostos sobre os objetos a serem notificados;
- Quando uma abstração possuir dois aspectos e um depende do outro;
- Quando não desejamos um forte acoplamento com os objetos que necessitam conhecer estas modificações;
-Permite um acoplamento mínimo entre o Subject e o Observer;
-Pode reutilizar Subjects sem reutilizar os seus Observers e vice-versa;
-Os Observers podem ser adicionados sem modificar o Subject;
-O Subject e Observer podem pertencer a diferentes camadas de abstração;
-O Subjeito e Observador podem pertencer a diferentes camadas de abstração;
Os assinantes são notificados em ordem aleatória. Também pode ocorrer o problema de vazamento de memória devido ao registro explícito e ao cancelamento do registro do Observer.
Como exemplo de aplicação do padrão vamos imaginar o seguinte cenário:
1- 3 usuários visitam um site de vendas on line para comprar o mesmo celular - um IPhone 11 :
Acontece que no momento este celular não esta disponível ou seja a loja esta sem estoque e assim não é possível comprar o produto no momento.
Para estes casos o site oferece uma opção para notificar o usuário quando o produto estiver disponível. Para isso os usuários tem que se registrar no serviço marcando a opção para serem notificados quando o celular chegar. Assim quando o celular IPhone 11 chegar os usuários receberam uma notificação do site.
Então após algum tempo a loja do site recebeu o produto e o seus status passou de - Sem Estoque - para - Disponível - e com isso o site enviou notificações para todos os usuários que se registraram no serviço.
Aqui podemos identificar os dois componentes principais do padrão Observer :
- O Celular IPhone 11 representa o Subject;
- Os usuários são os Observers;
E assim de acordo com o padrão Observer, os Observers precisam estar registrados para o Subject. No nosso caso, os três usuários estão cadastrados para a opção de notificação do Subject. Quando o estado do Subjcet mudar de - Sem Estoque - para Disponível - o Subject enviará uma notificação a todos os observers.
Temos aqui um exemplo de atuação do padrão observer a qual iremos implementar via código usando o C#.
Levando em conta este cenário vamos implementar o padrão Observer usando uma aplicação Console .NET Core (.NET 5.0) criada no VS 2019 Community.
1- ISubject - Define o contrato para registrar, remover e notificar Observers;
2 -ConcreteSubject - Define uma lista de observers e o produto cujo estado será observado e cria um objeto produto e define seu status inicial (subject);
- define o método para retornar a disponibilidade atual do produto;
- Altera o status do produto definindo sua disponibilidade atual;
- Registrar um observer interessado em recebe notificações sobre atualização do status de produto;
- Define um método para incluir o observer na lista de observadores;
- Define um método para remover o observer da lista de observadores;
- Notifica os observers cadastrados na lista de observadores;
3- IObserver - Define o contrato para atualizar os objetos que devem ser notificados das mudanças no status do produto
4- ConcreteObserver - Implementa a interface de atualização do Observer e mantêm referencia ao objeto ConcreteSubject;
1- A interface ISubject
void RegistrarObserver(IObserver observer);
void RemoverObserver(IObserver observer);
2- A Interface IObserver
void Atualiza(string disponibilidade);
3- Classe ConcreteSubject
namespace ObserverExemplo
private string Produto { get; set; }
private int Preco { get; set; }
private string Disponibilidade { get; set; }
public ConcreteSubject(string produto, int preco, string status)
Disponibilidade = status;
public string GetDisponibilidade()
return Disponibilidade;
public void SetDisponibilidade(string status)
this.Disponibilidade = status;
Console.WriteLine("A disponibilidade mudou de 'Sem Estoque' para 'Disponível'.");
public void RegistrarObserver(IObserver observer)
Console.WriteLine("Observer Adicionado : " + ((ConcreteObserver)observer).Usuario);
public void AdicionarObservers(IObserver observer)
public void RemoverObserver(IObserver observer)
Console.WriteLine($"O Produto :{Produto} no valor de R$ {Preco} agora esta disponível." +
"\n### Notificando todos os Observers registrados ### ");
observer.Atualiza(Disponibilidade);
4- Classe ConcreteObserver
public ConcreteObserver(string nome, ISubject subject)
Usuario = nome;
public void Atualiza(string disponibilidade)
Console.WriteLine($"Olá {Usuario}, o Produto que você deseja agora " +
$"esta {disponibilidade} em nosso site");
//cria um produto sem estoque e exibe disponibilidade
ConcreteSubject IPhone11 = new ConcreteSubject("Phone 11 ", 4900, "Sem Estoque");
Console.WriteLine("Phone 11 - estado atual : " + IPhone11.GetDisponibilidade());
Console.WriteLine("\nObservers inscritos para receber notificações sobre " +
"o produto IPhone 11\n");
//cria Usuario Macoratti e registra objeto no Subject
ConcreteObserver macoratti = new ConcreteObserver("Macoratti", IPhone11);
//cria Usuario Miriam e registra objeto no Subject
ConcreteObserver miriam = new ConcreteObserver("Miriam", IPhone11);
//cria Usuario Janice e registra objeto user1 no Subject
ConcreteObserver janice = new ConcreteObserver("Janice", IPhone11);
Console.WriteLine("\nPressione algo para alterar a disponibilidade e " +
"notificar os observers\n");
//altera status do Subject e notifica observers
IPhone11.SetDisponibilidade("Disponível");
O padrão Observer talvez seja um dos padrões de projetos mais usados, principalmente para aplicações web. Conhecer e saber aplicar os conceitos envolvidos neste padrão deve ser um quesito imprescindível para todo o desenvolvedor.