Hura! Mamy wreszcie przyjemność udostępnić wam polską wersję! Zapraszamy do przesyłania wiadomości z waszymi uwagami i informacjami o zauważonych błędach.
Obserwator

Obserwator w języku Go

Obserwator to behawioralny wzorzec projektowy pozwalający obiektom powiadamiać inne obiekty o zmianach swojego stanu.

Obserwator daje możliwość subskrypcji lub zrezygnowania z subskrypcji zdarzeń dowolnego obiektu implementującego interfejs subskrybenta.

Przykład koncepcyjny

Na stronie internetowej e-commerce co jakiś czas wyczerpuje się zapas niektórych artykułów. Może się zdarzyć, że klient chce kupić coś, czego akurat sklep nie ma na stanie. Są trzy rozwiązania takiego problemu:

  1. Klient co jakiś czas sprawdza dostępność artykułu na stronie.
  2. Aplikacja rozsyła wszystkim klientom informacje o wszystkich nowych pozycjach w katalogu które są dostępne.
  3. Klient subskrybuje informacje o jednym konkretnym produkcie który go interesuje. Wielu klientów może być w ten sposób powiadamianych odnośnie dostępności jakiegoś produktu.

Najsensowniejsza jest trzecia opcja i to właśnie jest podejście proponowane przez wzorzec Obserwator. Głównymi komponentami wchodzącymi w skład tego wzorca są:

  • Podmiot, czyli instancja publikująca informacje o zaistniałych zdarzeniach.
  • Obserwator, który subskrybuje zdarzenia dotyczące danego podmiotu i jest o nich powiadamiany.

subject.go: Podmiot

package main

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

item.go: Konkretny podmiot

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: Obserwator

package main

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

customer.go: Konkretny obserwator

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: Kod klienta

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: Wynik działania

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
Na podstawie: Golang By Example

Obserwator w innych językach

Wzorce projektowe: Obserwator w języku Java Wzorce projektowe: Obserwator w języku C# Wzorce projektowe: Obserwator w języku C++ Wzorce projektowe: Obserwator w języku PHP Wzorce projektowe: Obserwator w języku Python Wzorce projektowe: Obserwator w języku Ruby Wzorce projektowe: Obserwator w języku Swift Wzorce projektowe: Obserwator w języku TypeScript