Friend spotlight!
Whimsical Animations course
Friend spotlight!
NEW Whimsical Animations course
Friend spotlight! NEW Whimsical Animations course
huge discount only this week
Friend spotlight! Want to make your project stand out? NEW Whimsical Animations course huge discount only this week
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

Obserwator w innych językach

Obserwator w języku C# Obserwator w języku C++ Obserwator w języku Java Obserwator w języku PHP Obserwator w języku Python Obserwator w języku Ruby Obserwator w języku Rust Obserwator w języku Swift Obserwator w języku TypeScript