¡Hurra! ¡La versión en español se lanzó por fin! Por favor, envíanos un mensaje si quieres compartir tu opinión o reportar un error.
Observer

Observer en Go

Observer es un patrón de diseño de comportamiento que permite a un objeto notificar a otros objetos sobre cambios en su estado.

El patrón Observer proporciona una forma de suscribirse y cancelar la subscripción a estos eventos para cualquier objeto que implementa una interfaz suscriptora.

Ejemplo conceptual

En el sitio web de comercio electrónico, los artículos se agotan de vez en cuando. Puede haber clientes interesados en un artículo concreto que se agotó. Hay tres soluciones a este problema:

  1. El cliente comprueba la disponibilidad del artículo cada cierto tiempo.
  2. El comercio electrónico bombardea a los clientes con los nuevos artículos disponibles en stock.
  3. El cliente se suscribe tan solo al artículo particular en el que está interesado y recibe notificaciones si éste se encuentra disponible. Además, varios clientes pueden suscribirse al mismo producto.

La opción 3 es la más viable, y en esto consiste el patrón Observer. Los principales componentes del patrón Observer son:

  • Sujeto, la instancia que publica un evento cuando sucede algo.
  • Observador, que se inscribe a los eventos del sujeto y recibe notificaciones cuando suceden.

subject.go: Sujeto

package main

type subject interface {
	register(Observer observer)
	deregister(Observer observer)
	notifyAll()
}

item.go: Sujeto concreto

package main

import "fmt"

type item struct {
	observerList []observer
	name         string
	inStock      bool
}

func newItem(name string) *item {
	return &item{
		name: name,
	}
}
func (i *item) updateAvailability() {
	fmt.Printf("Item %s is now in stock\n", i.name)
	i.inStock = true
	i.notifyAll()
}
func (i *item) register(o observer) {
	i.observerList = append(i.observerList, o)
}

func (i *item) deregister(o observer) {
	i.observerList = removeFromslice(i.observerList, o)
}

func (i *item) notifyAll() {
	for _, observer := range i.observerList {
		observer.update(i.name)
	}
}

func removeFromslice(observerList []observer, observerToRemove observer) []observer {
	observerListLength := len(observerList)
	for i, observer := range observerList {
		if observerToRemove.getID() == observer.getID() {
			observerList[observerListLength-1], observerList[i] = observerList[i], observerList[observerListLength-1]
			return observerList[:observerListLength-1]
		}
	}
	return observerList
}

observer.go: Observador

package main

type observer interface {
	update(string)
	getID() string
}

customer.go: Observador concreto

package main

import "fmt"

type customer struct {
	id string
}

func (c *customer) update(itemName string) {
	fmt.Printf("Sending email to customer %s for item %s\n", c.id, itemName)
}

func (c *customer) getID() string {
	return c.id
}

main.go: Código cliente

package main

func main() {

	shirtItem := newItem("Nike Shirt")

	observerFirst := &customer{id: "abc@gmail.com"}
	observerSecond := &customer{id: "xyz@gmail.com"}

	shirtItem.register(observerFirst)
	shirtItem.register(observerSecond)

	shirtItem.updateAvailability()
}

output.txt: Resultado de la ejecución

Item Nike Shirt is now in stock
Sending email to customer abc@gmail.com for item Nike Shirt
Sending email to customer xyz@gmail.com for item Nike Shirt

Observer en otros lenguajes

Patrones de diseño: Observer en Java Patrones de diseño: Observer en C# Patrones de diseño: Observer en C++ Patrones de diseño: Observer en PHP Patrones de diseño: Observer en Python Patrones de diseño: Observer en Ruby Patrones de diseño: Observer en Swift Patrones de diseño: Observer en TypeScript