Menu
Coddy logo textTech

Observer Kalıbı

Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 89 / 107.

Observer deseni, nesneler arasında bire-çok ilişkisini tanımlar. Bir nesne (konu) durumunu değiştirdiğinde, ona bağlı tüm nesneler (gözlemciler) otomatik olarak bilgilendirilir. Bu, olay sistemleri, bildirimler veya birden fazla bileşenin değişikliklere tepki vermesi gereken her senaryo için idealdir.

Go'da bu modeli, gözlemciler için bir arayüz ve abonelikleri yöneten bir subject yapısı kullanarak uygularız:

type Observer interface {
    Update(event string)
}

type Subject struct {
    observers []Observer
}

func (s *Subject) Subscribe(o Observer) {
    s.observers = append(s.observers, o)
}

func (s *Subject) Notify(event string) {
    for _, observer := range s.observers {
        observer.Update(event)
    }
}

Observer arayüzünü uygulayan herhangi bir tür, bildirimleri almak için abone olabilir:

type EmailAlert struct{ Address string }

func (e EmailAlert) Update(event string) {
    fmt.Printf("Email to %s: %s\n", e.Address, event)
}

type Logger struct{}

func (l Logger) Update(event string) {
    fmt.Println("Log:", event)
}

Özne, somut türlerini bilmeden tüm gözlemcileri bilgilendirir:

subject := &Subject{}
subject.Subscribe(EmailAlert{Address: "user@example.com"})
subject.Subscribe(Logger{})

subject.Notify("Order placed")
// E-posta user@example.com adresine: Sipariş verildi
// Log: Sipariş verildi

Bu tasarım kalıbı, özneyi gözlemcilerinden ayırarak mevcut kodu değiştirmeden yeni gözlemci türleri eklemeyi kolaylaştırır. Olay güdümlü mimarilerde, GUI çerçevelerinde ve yayınla/abone ol mesajlaşma sistemlerinde yaygın olarak kullanılır.

challenge icon

Görev

Kolay

Observer desenini kullanarak bir hisse senedi fiyatı uyarı sistemi oluşturalım! Bir hisse senedinin fiyatı her değiştiğinde birden çok uyarı hizmetinin otomatik olarak bildirim aldığı bir sistem oluşturacaksın. Bu, subject'in somut türlerini bilmeden observer'ların event'lere nasıl tepki verebildiğini göstermek için idealdir.

Kodunu üç dosyaya ayıracaksın:

  • observer.go: observer interface'ini ve somut observer türlerini Define et.

    Fiyatlar değiştiğinde hisse senedi bilgilerini alan Update(stockName string, price float64) method'una sahip bir Observer interface'i Create et.

    İki observer türü Implement et:

    • PriceAlert; bir Threshold alanına (float64) sahip olmalı ve güncellendiğinde, fiyat eşikten yüksekse ALERT: [stockName] at $[price] crossed threshold $[threshold], düşükse WATCHING: [stockName] at $[price] (threshold: $[threshold]) döndürmelidir
    • PriceLogger; bir LogName alanına (string) sahip olmalı ve güncellendiğinde [logName] recorded [stockName]: $[price] döndürmelidir

    Her iki observer da biçimlendirilmiş yanıt metnini döndüren bir method'a sahip olmalıdır.

  • stock.go: observer'ları yöneten ve fiyat değişikliklerini onlara bildiren subject'i Create et.

    Name (string), Price (float64) alanlarına ve bir observer dilimine sahip bir Stock struct'ı oluştur. Aşağıdaki method'ları Add et:

    • Bir observer eklemek için Subscribe(o Observer)
    • Fiyatı güncelleyen, tüm observer'lara bildirim gönderen ve tüm yanıtlarının bir dilimini döndüren SetPrice(price float64) []string

    Ayrıca bir NewStock(name string, initialPrice float64) *Stock constructor'ı oluştur.

  • main.go: Stock'u observer'larla kur ve fiyat değişikliklerini simüle et.

    Hisse senedi adını ve başlangıç fiyatını oku. Ardından oluşturulacak observer sayısını oku. Her observer için türünü (alert veya logger) ve configuration değerini (alert'ler için eşik, logger'lar için log adı) oku. Her observer'ı Stock'a Subscribe et.

    Son olarak yeni bir fiyat oku, Stock'u güncelle ve her observer'ın yanıtını kendi satırına yazdır.

Aşağıdaki girdiler sağlanacaktır:

  • 1. satır: Hisse senedi adı
  • 2. satır: Başlangıç fiyatı
  • 3. satır: Observer sayısı
  • Her observer için: tür (alert veya logger), ardından configuration değeri
  • Son satır: Ayarlanacak yeni fiyat

Tüm fiyatları iki ondalık basamakla Format et.

Örneğin, şu girdi verildiğinde:

GOOG
150.00
3
alert
155.00
logger
TradeLog
alert
140.00
160.50

Çıktın şöyle olmalıdır:

ALERT: GOOG at $160.50 crossed threshold $155.00
TradeLog recorded GOOG: $160.50
ALERT: GOOG at $160.50 crossed threshold $140.00

Ve şu girdi verildiğinde:

AAPL
180.00
2
logger
DailyLog
alert
200.00
175.25

Çıktın şöyle olmalıdır:

DailyLog recorded AAPL: $175.25
WATCHING: AAPL at $175.25 (threshold: $200.00)

Stock'un alert'lere mi yoksa logger'lara mı bildirim gönderdiğini bilmediğine dikkat et. Yalnızca her observer üzerinde Update çağrısı yapar. Bu ayrıştırma, Stock kodunu değiştirmeden yeni observer türleri eklemeyi kolaylaştırır!

Kendin dene

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Stok adını oku
	stockName, _ := reader.ReadString('\n')
	stockName = strings.TrimSpace(stockName)

	// Başlangıç fiyatını oku
	initialPriceStr, _ := reader.ReadString('\n')
	initialPrice, _ := strconv.ParseFloat(strings.TrimSpace(initialPriceStr), 64)

	// Gözlemci sayısını oku
	numObserversStr, _ := reader.ReadString('\n')
	numObservers, _ := strconv.Atoi(strings.TrimSpace(numObserversStr))

	// TODO: NewStock yapıcısını kullanarak yeni bir Stock oluştur

	// TODO: Her gözlemci için döngü yap
	for i := 0; i < numObservers; i++ {
		// Gözlemci türünü oku ("alert" veya "logger")
		observerType, _ := reader.ReadString('\n')
		observerType = strings.TrimSpace(observerType)

		// Yapılandırma değerini oku
		configValue, _ := reader.ReadString('\n')
		configValue = strings.TrimSpace(configValue)

		// TODO: Türe göre uygun gözlemciyi oluştur
		// - "alert" için: configValue değerini float64 eşik olarak ayrıştır, PriceAlert oluştur
		// - "logger" için: configValue değerini LogName olarak kullan, PriceLogger oluştur
		// TODO: Gözlemciyi stoka abone et
	}

	// Yeni fiyatı oku
	newPriceStr, _ := reader.ReadString('\n')
	newPrice, _ := strconv.ParseFloat(strings.TrimSpace(newPriceStr), 64)

	// TODO: Yeni fiyatı ayarla ve yanıtları al

	// TODO: Her yanıtı kendi satırına yazdır
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online Go derleyicisi