1. Cos'è il pattern Observer

Il pattern Observer è un pattern di progettazione comportamentale utilizzato per stabilire una dipendenza uno-a-molti tra gli oggetti. In particolare, quando un oggetto (chiamato soggetto o osservabile) cambia, tutti i suoi dipendenti (chiamati osservatori) vengono notificati e aggiornati automaticamente. Questo pattern consente un accoppiamento debole tra soggetti e osservatori, conseguendo così un disaccoppiamento e una flessibilità tra gli oggetti.

2. Caratteristiche e vantaggi del pattern Observer

Il pattern Observer ha le seguenti caratteristiche e vantaggi:

  • Accoppiamento debole tra soggetti e osservatori, dove il soggetto non ha bisogno di conoscere i dettagli specifici dell'implementazione degli osservatori.
  • Aggiunta e rimozione dinamica degli osservatori, rendendo il sistema più flessibile.
  • Segue il principio aperto-chiuso tra soggetti e osservatori, consentendo l'estensione e la riutilizzabilità indipendenti.
  • Può stabilire una relazione di dipendenza uno-a-molti, in cui un soggetto può avere più osservatori.

3. Esempi di Applicazioni Pratiche del Pattern Observer

Il pattern Observer ha molte applicazioni pratiche nella vita reale, come:

  • Meccanismo di gestione degli eventi nelle interfacce GUI, come la gestione delle azioni quando si fa clic su un pulsante.
  • Push delle quotazioni in tempo reale del mercato azionario.
  • Notifica delle attività promozionali su piattaforme di e-commerce.

4. Implementazione del Pattern Observer in Golang

4.1 Diagramma delle classi UML

Pattern Observer in Golang

4.2 Introduzione dell'Esempio

In questo esempio, abbiamo un soggetto (Subject) e due osservatori (ObserverA e ObserverB). Il soggetto può registrare, annullare la registrazione e notificare gli osservatori.

4.3 Passi di Implementazione

4.3.1 Creare l'Interfaccia del Soggetto e la Classe Concreta del Soggetto

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

type ConcreteSubject struct {
    observers []Observer
}

// Registrare l'oggetto ascoltatore
func (subject *ConcreteSubject) RegisterObserver(observer Observer) {
    subject.observers = append(subject.observers, observer)
}

// Rimuovere l'oggetto ascoltatore
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
        }
    }
}

// Notificare gli eventi
func (subject *ConcreteSubject) NotifyObservers() {
    for _, observer := range subject.observers {
        observer.Update()
    }
}

4.3.2 Creare l'Interfaccia dell'Osservatore e le Classi Concreto dell'Osservatore

type Observer interface {
    Update()
}

type ConcreteObserverA struct {}

func (observer *ConcreteObserverA) Update() {
    fmt.Println("L'osservatore A è stato notificato.")
}

type ConcreteObserverB struct {}

func (observer *ConcreteObserverB) Update() {
    fmt.Println("L'osservatore B è stato notificato.")
}

4.4 Esempio di Codice Demo

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

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

    subject.NotifyObservers()

    subject.RemoveObserver(observerA)

    subject.NotifyObservers()
}

Output:

L'osservatore A è stato notificato.
L'osservatore B è stato notificato.
L'osservatore B è stato notificato.

Il codice di esempio sopra dimostra l'implementazione specifica del pattern observer. Il soggetto (ConcreteSubject) ha registrato due osservatori (ObserverA e ObserverB) e poi ha notificato questi due osservatori. Dopo di che, l'osservatore A è stato disiscritto dal soggetto e l'osservatore rimasto B è stato notificato nuovamente.