Menu
CoddyTech

Pola Observer

Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan GO di Coddy. Pelajaran 89 dari 107.

Observer pattern mendefinisikan hubungan satu-ke-banyak antar-object. Saat satu object (subjek) berubah keadaan, semua dependennya (observer) akan diberi tahu secara otomatis. Pola ini ideal untuk sistem event, notifikasi, atau skenario apa pun yang mengharuskan beberapa komponen bereaksi terhadap perubahan.

Di Go, kita menerapkan pola ini menggunakan interface untuk observer dan struct subject yang mengelola langganan:

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)
    }
}

Tipe apa pun yang mengimplementasikan interface Observer dapat berlangganan untuk menerima notifikasi:

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)
}

Subjek memberi tahu semua pengamat tanpa mengetahui tipe konkretnya:

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

subject.Notify("Order placed")
// Email ke user@example.com: Pesanan dibuat
// Log: Pesanan dibuat

Pola ini memisahkan subject dari para observer-nya, sehingga kamu dapat dengan mudah menambahkan jenis observer baru tanpa mengubah kode yang sudah ada. Pola ini umum digunakan dalam arsitektur berbasis peristiwa, framework GUI, dan sistem pesan pub/sub.

challenge icon

Tantangan

Mudah

Mari buat sistem peringatan harga saham menggunakan pola Observer! Kamu akan membuat sistem tempat beberapa layanan peringatan secara otomatis menerima notifikasi setiap kali harga saham berubah. Ini cocok untuk menunjukkan cara observer dapat merespons peristiwa tanpa mengetahui tipe konkret subject.

Kamu akan mengatur kodemu dalam tiga file:

  • observer.go: Definisikan interface observer dan tipe observer konkret.

    Buat interface Observer dengan method Update(stockName string, price float64) yang menerima informasi saham saat harga berubah.

    Implementasikan dua tipe observer:

    • PriceAlert dengan field Threshold (float64), saat diperbarui, mengembalikan ALERT: [stockName] at $[price] crossed threshold $[threshold] jika harga berada di atas ambang batas, atau WATCHING: [stockName] at $[price] (threshold: $[threshold]) jika berada di bawah
    • PriceLogger dengan field LogName (string), saat diperbarui, mengembalikan [logName] recorded [stockName]: $[price]

    Kedua observer harus memiliki method yang mengembalikan string respons berformat.

  • stock.go: Buat subject yang mengelola observer dan memberi tahu mereka tentang perubahan harga.

    Buat struct Stock dengan field untuk Name (string), Price (float64), dan slice observer. Tambahkan method berikut:

    • Subscribe(o Observer) untuk menambahkan observer
    • SetPrice(price float64) []string yang memperbarui harga dan memberi tahu semua observer, lalu mengembalikan slice berisi semua respons mereka

    Buat juga konstruktor NewStock(name string, initialPrice float64) *Stock.

  • main.go: Siapkan saham beserta observer-nya, lalu simulasikan perubahan harga.

    Baca nama saham dan harga awal. Lalu baca jumlah observer yang akan dibuat. Untuk setiap observer, baca tipenya (alert atau logger) dan konfigurasinya (ambang batas untuk peringatan, nama log untuk logger). Langgan­kan setiap observer ke saham.

    Terakhir, baca harga baru, perbarui saham, lalu cetak respons setiap observer pada barisnya sendiri.

Input berikut akan diberikan:

  • Baris 1: Nama saham
  • Baris 2: Harga awal
  • Baris 3: Jumlah observer
  • Untuk setiap observer: tipe (alert atau logger), lalu nilai konfigurasi
  • Baris terakhir: Harga baru yang akan ditetapkan

Format semua harga dengan dua angka desimal.

Contohnya, jika diberikan:

GOOG
150.00
3
alert
155.00
logger
TradeLog
alert
140.00
160.50

Output yang diharapkan:

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

Jika diberikan:

AAPL
180.00
2
logger
DailyLog
alert
200.00
175.25

Output yang diharapkan:

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

Perhatikan bahwa Stock tidak mengetahui apakah ia sedang memberi tahu alert atau logger. Stock hanya memanggil Update pada setiap observer. Pemisahan ini memudahkan kamu menambahkan tipe observer baru tanpa mengubah kode Stock!

Coba sendiri

package main

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

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

	// Baca nama saham
	stockName, _ := reader.ReadString('\n')
	stockName = strings.TrimSpace(stockName)

	// Baca harga awal
	initialPriceStr, _ := reader.ReadString('\n')
	initialPrice, _ := strconv.ParseFloat(strings.TrimSpace(initialPriceStr), 64)

	// Baca jumlah observer
	numObserversStr, _ := reader.ReadString('\n')
	numObservers, _ := strconv.Atoi(strings.TrimSpace(numObserversStr))

	// TODO: Buat Stock baru menggunakan konstruktor NewStock

	// TODO: Lakukan perulangan untuk setiap observer
	for i := 0; i < numObservers; i++ {
		// Baca tipe observer ("alert" atau "logger")
		observerType, _ := reader.ReadString('\n')
		observerType = strings.TrimSpace(observerType)

		// Baca nilai konfigurasi
		configValue, _ := reader.ReadString('\n')
		configValue = strings.TrimSpace(configValue)

		// TODO: Buat observer yang sesuai berdasarkan tipenya
		// - Untuk "alert": ubah configValue menjadi ambang batas bertipe float64, lalu buat PriceAlert
		// - Untuk "logger": gunakan configValue sebagai LogName, lalu buat PriceLogger
		// TODO: Daftarkan observer ke saham
	}

	// Baca harga baru
	newPriceStr, _ := reader.ReadString('\n')
	newPrice, _ := strconv.ParseFloat(strings.TrimSpace(newPriceStr), 64)

	// TODO: Tetapkan harga baru dan dapatkan tanggapan

	// TODO: Cetak setiap tanggapan pada baris tersendiri
}
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Objek

Latihan sendiri: Compiler Go online