1. ¿Qué es el Patrón Observer?

El Patrón Observer es un patrón de diseño de comportamiento utilizado para establecer una dependencia uno a muchos entre objetos. Específicamente, cuando un objeto (llamado sujeto u observable) cambia, todas sus dependencias (llamadas observadores) son notificadas y actualizadas automáticamente. Este patrón permite un acoplamiento suelto entre sujetos y observadores, logrando así el desacoplamiento y la flexibilidad entre objetos.

2. Características y Ventajas del Patrón Observer

El Patrón Observer tiene las siguientes características y ventajas:

  • Acoplamiento suelto entre sujetos y observadores, donde el sujeto no necesita conocer los detalles de implementación específicos de los observadores.
  • Adición y eliminación dinámica de observadores, lo que hace que el sistema sea más flexible.
  • Sigue el principio de abierto-cerrado entre sujetos y observadores, lo que permite la extensión y reutilización independientes.
  • Puede establecer una relación de dependencia uno a muchos, donde un sujeto puede tener múltiples observadores.

3. Ejemplos de Aplicaciones Prácticas del Patrón Observer

El Patrón Observer tiene muchas aplicaciones prácticas en la vida real, como:

  • Mecanismo de manejo de eventos en interfaces gráficas de usuario, como el manejo de acciones cuando se hace clic en un botón.
  • Cotizaciones en tiempo real del mercado de valores.
  • Notificación de actividades promocionales en plataformas de comercio electrónico.

4. Implementación del Patrón Observer en Golang

4.1 Diagrama de Clases UML

Patrón Observer en Golang

4.2 Introducción del Ejemplo

En este ejemplo, tenemos un sujeto (Subject) y dos observadores (ObserverA y ObserverB). El sujeto puede registrar, eliminar y notificar a los observadores.

4.3 Pasos de Implementación

4.3.1 Crear la Interfaz del Sujeto y la Clase de Sujeto Concreto

type Subject interface {
    RegisterObserver(observer Observer)
    RemoveObserver(observer Observer)
    NotifyObservers()
}

type ConcreteSubject struct {
    observers []Observer
}

// Registrar objeto observador
func (subject *ConcreteSubject) RegisterObserver(observer Observer) {
    subject.observers = append(subject.observers, observer)
}

// Eliminar objeto observador
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
        }
    }
}

// Activar notificación de evento
func (subject *ConcreteSubject) NotifyObservers() {
    for _, observer := range subject.observers {
        observer.Update()
    }
}

4.3.2 Crear la Interfaz del Observador y las Clases de Observador Concreto

type Observer interface {
    Update()
}

type ConcreteObserverA struct {}

func (observer *ConcreteObserverA) Update() {
    fmt.Println("El observador A ha sido notificado.")
}

type ConcreteObserverB struct {}

func (observer *ConcreteObserverB) Update() {
    fmt.Println("El observador B ha sido notificado.")
}

4.4 Demo de Código de Ejemplo

func main() {
    subject := &ConcreteSubject{}
    observerA := &ConcreteObserverA{}
    observerB := &ConcreteObserverB{}

    subject.RegisterObserver(observerA)
    subject.RegisterObserver(observerB)

    subject.NotifyObservers()

    subject.RemoveObserver(observerA)

    subject.NotifyObservers()
}

Salida:

El observador A ha sido notificado.
El observador B ha sido notificado.
El observador B ha sido notificado.

El código de ejemplo anterior demuestra la implementación específica del patrón observer. El sujeto (ConcreteSubject) registró dos observadores (ObserverA y ObserverB), y luego notificó a estos dos observadores. Después, el observador A fue eliminado del sujeto y el observador restante, B, fue notificado nuevamente.