Padrão Observer
Parte da seção Programação Orientada a Objetos do Journey de PHP da Coddy. Lição 73 de 91.
O padrão Observer é um padrão comportamental de projeto que estabelece uma relação de um para muitos entre objetos. Quando um objeto (o sujeito) muda de estado, todos os seus dependentes (os observadores) são automaticamente notificados e atualizados.
Pense em uma assinatura de newsletter. A newsletter é o sujeito, e os assinantes são observadores. Quando uma nova edição é publicada, todos os assinantes a recebem automaticamente, sem que a newsletter precise conhecer os detalhes de cada assinante.
Aqui está uma implementação básica em PHP:
<?php
interface Observer {
public function update(string $message): void;
}
class Newsletter {
private array $subscribers = [];
public function subscribe(Observer $observer): void {
$this->subscribers[] = $observer;
}
public function publish(string $content): void {
foreach ($this->subscribers as $subscriber) {
$subscriber->update($content);
}
}
}
class EmailSubscriber implements Observer {
public function __construct(private string $email) {}
public function update(string $message): void {
echo "Sending to {$this->email}: $message\n";
}
}
$newsletter = new Newsletter();
$newsletter->subscribe(new EmailSubscriber("alice@example.com"));
$newsletter->subscribe(new EmailSubscriber("bob@example.com"));
$newsletter->publish("New article released!");
Saída:
Sending to alice@example.com: New article released!
Sending to bob@example.com: New article released!O padrão desacopla o assunto de seus observadores. A classe Newsletter não precisa saber se está notificando assinantes de e-mail, assinantes de SMS ou serviços de notificações push. Ela simplesmente chama update() em qualquer elemento que implemente a interface Observer. Isso torna fácil adicionar novos tipos de observadores sem modificar o código existente.
Desafio
FácilVamos criar um sistema de alertas de preço de ações usando o Padrão Observer. Quando o preço de uma ação muda, todos os investidores registrados devem ser notificados automaticamente: uma aplicação perfeita desse padrão no mundo real.
Você organizará seu código em quatro arquivos:
Observer.php: Defina uma interfaceObservercom um único métodoupdate(string $stockName, float $price): void. Esse é o contrato que todos os observadores devem seguir para receber notificações.Investors.php: Inclua o arquivo Observer e crie duas classes que implementem a interface:EmailInvestor: Recebe um endereço de e-mail em seu construtor (use a promoção de propriedades no construtor). Seu métodoupdate()imprime"Email to [email]: [stockName] is now $[price]"SmsInvestor: Recebe um número de telefone em seu construtor. Seu métodoupdate()imprime"SMS to [phone]: [stockName] is now $[price]"
Stock.php: Inclua o arquivo Observer e crie uma classeStockque atua como o assunto. Sua ação deve:- Armazenar o nome da ação e o preço atual (use a promoção de propriedades no construtor para o nome e inicialize o preço como
0.0) - Manter um array privado de observadores
- Ter um método
subscribe(Observer $observer): voidpara adicionar observadores - Ter um método
setPrice(float $price): voidque atualiza o preço e notifica todos os observadores
update()de cada observador com o nome da ação e o novo preço.- Armazenar o nome da ação e o preço atual (use a promoção de propriedades no construtor para o nome e inicialize o preço como
main.php: Inclua os arquivos Investors e Stock. Você receberá três entradas: um nome de ação, um endereço de e-mail e um número de telefone.Crie um
Stockcom o nome fornecido. Inscreva umEmailInvestorcom o endereço de e-mail e umSmsInvestorcom o número de telefone.Defina o preço da ação como
150.50para acionar notificações para todos os inscritos.
O Padrão Observer mantém sua classe Stock desacoplada dos métodos específicos de notificação. Você poderia facilmente adicionar um PushInvestor ou SlackInvestor mais tarde sem modificar a classe Stock.
Experimente você mesmo
<?php
require_once 'Investors.php';
require_once 'Stock.php';
// Ler entradas
$stockName = trim(fgets(STDIN));
$email = trim(fgets(STDIN));
$phone = trim(fgets(STDIN));
// TODO: Crie um Stock com o nome fornecido
// TODO: Inscreva um EmailInvestor com o endereço de e-mail
// TODO: Inscreva um SmsInvestor com o número de telefone
// TODO: Defina o preço do stock para 150.50 para acionar as notificações
?>Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP
Arquivos externosIntrodução à OOPClasses vs. objetosA palavra-chave $thisMétodosPropriedadesConstrutor (__construct)Destrutor (__destruct)Recapitulação - Calculadora simples4Herança
Herança BásicaA Palavra-chave parent::Sobrescrita de MétodosA Palavra-chave finalClasses AbstratasRecapitulação - Hierarquia de Funcionários7Encapsulamento
Público, Protegido, PrivadoModificadores de Acesso em ProfundidadeGetters e SettersOcultação de InformaçõesPromoção de Construtor (8.0)Recapitulação - Sistema de Registros de Alunos10Conceitos Avançados de OOP
Composição vs. HerançaInjeção de DependênciaClasses AnônimasEnums (PHP 8.1)Fibras (PHP 8.1)Análise Profunda da Clonagem de ObjetosGeradores e Iteradores13Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Repository2Namespaces e Autoloading
Introdução a NamespacesA palavra-chave usePadrão de Autoloading PSR-4Autoloader do ComposerRecapitulação - Projeto organizado5Interfaces e Contratos
Introdução às InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesInterface vs Classe AbstrataTipagem com InterfacesRecapitulação - Calculadora de Formas8Métodos Mágicos
Introdução aos Métodos Mágicos__toString e __debugInfo__get, __set, __isset, __unset__call e __callStatic__clone e Clonagem de Objetos__serialize e __unserializeRecapitulação - Coleção Personalizada11Sistema de Tipos e Tratamento de Erros
Declarações de TiposTipos NulosTipos de União e InterseçãoClasses de ExceçãoHierarquia de Exceções PersonalizadaTry, Catch, FinallyRecapitulação - Validador de Formulário14Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses de Livros e Usuários3Propriedades de Classes
Propriedades de Instância vs. EstáticasConstantes em ClassesMétodos e Propriedades EstáticosPropriedades Privadas e ProtegidasPropriedades Somente para Leitura (PHP 8.1)Recapitulação - Gerenciador de Contas Bancárias6Polimorfismo
Revisão da Sobrescrita de MétodosPolimorfismo via InterfacesIndicação de Tipos e Tipos UnionVinculação Estática TardiaRecapitulação - Processador de Pagamentos9Traits
Introdução a TraitsUsando Múltiplos TraitsResolução de Conflitos entre TraitsMétodos Abstratos em TraitsTraits vs. Herança12Padrões de Projeto – Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão StrategyPratique por conta própria: Compilador de PHP online