1. O que é o Padrão Observer
O Padrão Observer é um padrão de design comportamental usado para estabelecer uma dependência de um para muitos entre objetos. Especificamente, quando um objeto (referido como o sujeito ou observável) muda, todas as suas dependências (chamadas observadores) são notificadas e atualizadas automaticamente. Este padrão permite um acoplamento frouxo entre sujeitos e observadores, alcançando assim o desacoplamento e flexibilidade entre os objetos.
2. Características e Vantagens do Padrão Observer
O Padrão Observer possui as seguintes características e vantagens:
- Acoplamento frouxo entre sujeitos e observadores, onde o sujeito não precisa conhecer os detalhes de implementação específicos dos observadores.
- Adição e remoção dinâmicas de observadores, tornando o sistema mais flexível.
- Segue o princípio aberto-fechado entre sujeitos e observadores, possibilitando extensão independente e reutilização.
- Pode estabelecer uma relação de dependência de um para muitos, onde um sujeito pode ter vários observadores.
3. Exemplos de Aplicações Práticas do Padrão Observer
O Padrão Observer possui muitas aplicações práticas na vida real, tais como:
- Mecanismo de tratamento de eventos em interfaces GUI, como o tratamento de ações quando um botão é clicado.
- Cotações em tempo real do mercado de ações.
- Notificação de atividades promocionais em plataformas de e-commerce.
4. Implementação do Padrão Observer em Golang
4.1 Diagrama de Classes UML
4.2 Introdução do Exemplo
Neste exemplo, temos um sujeito (Subject) e dois observadores (ObserverA e ObserverB). O sujeito pode registrar, remover e notificar observadores.
4.3 Etapas de Implementação
4.3.1 Criar Interface do Sujeito e Classe de Sujeito Concreto
type Subject interface {
RegisterObserver(observer Observer)
RemoveObserver(observer Observer)
NotifyObservers()
}
type ConcreteSubject struct {
observers []Observer
}
// Registrar objeto ouvinte
func (subject *ConcreteSubject) RegisterObserver(observer Observer) {
subject.observers = append(subject.observers, observer)
}
// Remover objeto ouvinte
func (subject *ConcreteSubject) RemoveObserver(observer Observer) {
for i, obs := range subject.observers {
if obs == observer {
subject.observers = append(subject.observers[:i], subject.observers[i+1:]...)
break
}
}
}
// Acionar notificação de evento
func (subject *ConcreteSubject) NotifyObservers() {
for _, observer := range subject.observers {
observer.Update()
}
}
4.3.2 Criar Interface de Observador e Classes de Observador Concreto
type Observer interface {
Update()
}
type ConcreteObserverA struct {}
func (observer *ConcreteObserverA) Update() {
fmt.Println("O Observador A foi notificado.")
}
type ConcreteObserverB struct {}
func (observer *ConcreteObserverB) Update() {
fmt.Println("O Observador B foi notificado.")
}
4.4 Demonstração do Código de Exemplo
func main() {
subject := &ConcreteSubject{}
observerA := &ConcreteObserverA{}
observerB := &ConcreteObserverB{}
subject.RegisterObserver(observerA)
subject.RegisterObserver(observerB)
subject.NotifyObservers()
subject.RemoveObserver(observerA)
subject.NotifyObservers()
}
Saída:
O Observador A foi notificado.
O Observador B foi notificado.
O Observador B foi notificado.
O código de exemplo acima demonstra a implementação específica do padrão observer. O sujeito (ConcreteSubject) registrou dois observadores (ObserverA e ObserverB) e então notificou esses dois observadores. Depois disso, o observador A foi removido do sujeito e o observador B restante foi notificado novamente.