1. Co to jest wzorzec Obserwatora

Wzorzec Obserwatora to behawioralny wzorzec projektowy używany do ustanowienia zależności jeden do wielu między obiektami. Konkretnie, gdy obiekt (nazywany podmiotem lub obserwowalnym) ulega zmianie, wszyscy jego zależności (nazywani obserwatorami) są powiadamiani i automatycznie aktualizowani. Ten wzorzec umożliwia luźne powiązanie między podmiotami a obserwatorami, co pozwala na osiągnięcie odseparowania i elastyczności między obiektami.

2. Charakterystyka i Zalety wzorca Obserwatora

Wzorzec Obserwatora ma następujące cechy i zalety:

  • Luźne powiązanie między podmiotami a obserwatorami, gdzie podmiot nie musi znać konkretnych szczegółów implementacyjnych obserwatorów.
  • Dynamiczne dodawanie i usuwanie obserwatorów, co sprawia, że system staje się bardziej elastyczny.
  • Zgodny z zasadą otwarte-zamknięte między podmiotami a obserwatorami, umożliwiający niezależne rozszerzanie i ponowne wykorzystanie.
  • Może ustanawiać zależność jeden do wielu, gdzie podmiot może mieć wielu obserwatorów.

3. Przykłady praktycznych zastosowań wzorca Obserwatora

Wzorzec Obserwatora ma wiele praktycznych zastosowań w życiu codziennym, takich jak:

  • Mechanizm obsługi zdarzeń w interfejsach GUI, np. obsługa akcji po kliknięciu przycisku.
  • Rzeczywiste notowania giełdowe w czasie rzeczywistym.
  • Powiadamianie o akcjach promocyjnych na platformach handlowych w internecie.

4. Implementacja wzorca Obserwatora w języku Golang

4.1 Diagram klas UML

Wzorzec Obserwatora w Golang

4.2 Wprowadzenie przykładu

W tym przykładzie mamy podmiot (Subject) i dwóch obserwatorów (ObserverA i ObserverB). Podmiot może rejestrować, wyrejestrowywać i powiadamiać obserwatorów.

4.3 Kroki implementacji

4.3.1 Utwórz interfejs Subject i klasę konkretnego podmiotu

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

type ConcreteSubject struct {
    observers []Observer
}

// Zarejestruj obiekt nasłuchujący
func (subject *ConcreteSubject) RegisterObserver(observer Observer) {
    subject.observers = append(subject.observers, observer)
}

// Usuń obiekt nasłuchujący
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
        }
    }
}

// Wywołaj powiadomienie o zdarzeniu
func (subject *ConcreteSubject) NotifyObservers() {
    for _, observer := range subject.observers {
        observer.Update()
    }
}

4.3.2 Utwórz interfejs Observer i klasy konkretnego obserwatora

type Observer interface {
    Update()
}

type ConcreteObserverA struct {}

func (observer *ConcreteObserverA) Update() {
    fmt.Println("Obserwator A został powiadomiony.")
}

type ConcreteObserverB struct {}

func (observer *ConcreteObserverB) Update() {
    fmt.Println("Obserwator B został powiadomiony.")
}

4.4 Przykładowy kod demonstracyjny

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

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

    subject.NotifyObservers()

    subject.RemoveObserver(observerA)

    subject.NotifyObservers()
}

Output:

Obserwator A został powiadomiony.
Obserwator B został powiadomiony.
Obserwator B został powiadomiony.

Powyższy przykładowy kod demonstruje konkretne zastosowanie wzorca obserwatora. Podmiot (ConcreteSubject) zarejestrował dwóch obserwatorów (ObserverA i ObserverB), a następnie powiadomił tych dwóch obserwatorów. Następnie obserwator A został wyrejestrowany z podmiotu, a pozostały obserwator B został ponownie powiadomiony.