Pola Observer
Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan Swift di Coddy. Pelajaran 44 dari 57.
Dalam pola observer, sebuah object (subject) menyimpan daftar observer dan memberi tahu semuanya saat sesuatu terjadi. Subject tidak perlu mengetahui apa yang dilakukan para observer:
final class Button {
private var handlers: [(String) -> Void] = []
func onTap(_ handler: @escaping (String) -> Void) {
handlers.append(handler)
}
func tap() {
for h in handlers { h("tapped") }
}
}
let b = Button()
b.onTap { print("logger saw \($0)") }
b.onTap { print("counter saw \($0)") }
b.tap()Output:
logger saw tapped
counter saw tappedObserver juga dapat berupa object yang mematuhi sebuah protokol. Subject memanggil method protokol pada setiap observer yang terdaftar:
protocol StockObserver: AnyObject {
func priceChanged(_ symbol: String, to price: Int)
}
final class Stock {
let symbol: String
private var observers: [StockObserver] = []
var price: Int { didSet { observers.forEach { $0.priceChanged(symbol, to: price) } } }
init(symbol: String, price: Int) { self.symbol = symbol; self.price = price }
func add(_ o: StockObserver) { observers.append(o) }
}
final class Alert: StockObserver {
func priceChanged(_ s: String, to p: Int) { if p > 100 { print("\(s) above 100: \(p)") } }
}
let apple = Stock(symbol: "AAPL", price: 90)
apple.add(Alert())
apple.price = 95
apple.price = 120Output:
AAPL above 100: 120Observer biasanya memerlukan cara untuk berhenti mendengarkan. Mengembalikan id (atau token) dari pendaftaran memungkinkan pemanggil menghapus observer-nya nanti:
final class EventBus {
private var listeners: [Int: (String) -> Void] = [:]
private var nextId = 0
func subscribe(_ f: @escaping (String) -> Void) -> Int {
nextId += 1
listeners[nextId] = f
return nextId
}
func unsubscribe(_ id: Int) { listeners[id] = nil }
func publish(_ event: String) {
for id in listeners.keys.sorted() { listeners[id]!(event) }
}
}
let bus = EventBus()
let a = bus.subscribe { print("A got \($0)") }
_ = bus.subscribe { print("B got \($0)") }
bus.publish("login")
bus.unsubscribe(a)
bus.publish("logout")Output:
A got login
B got login
B got logout@escaping menandai closure yang disimpan dan dipanggil nanti, setelah fungsi yang menerimanya selesai dijalankan. Pola observer menjaga agar subject dan observer tetap terhubung secara longgar: observer baru dapat ditambahkan tanpa mengubah subject.
func onTap(_ handler: @escaping (String) -> Void) {
handlers.append(handler) // disimpan: harus menggunakan @escaping
}Tantangan
MudahLengkapi class Newsletter, sebuah subjek yang mengirimkan terbitan kepada para pelanggan. subscribe(name:handler:) menyimpan closure dengan sebuah nama (berlangganan lagi dengan nama yang sama akan menggantinya), unsubscribe(name:) menghapusnya, dan publish(_ title:) memanggil setiap handler berdasarkan urutan alfabetis nama dan mengembalikan jumlah yang diberi tahu.
Kode yang disediakan membaca perintah sub <name>, unsub <name> atau pub <title>. Handler setiap pelanggan mencetak <name> reads <title>; setelah setiap pub, kode mencetak sent to 2.
Letakkan kodemu di Newsletter.swift. main.swift berisi kode input/output yang disediakan dan tidak boleh diedit.
Coba sendiri
// Kode input/output yang disediakan: biarkan apa adanya
var input: [String] = []
while let line = readLine() { input.append(line) }
let news = Newsletter()
for cmd in input {
let p = cmd.split(separator: " ", maxSplits: 1).map(String.init)
switch p[0] {
case "sub":
let name = p[1]
news.subscribe(name: name) { print("\(name) reads \($0)") }
case "unsub": news.unsubscribe(name: p[1])
default: print("sent to \(news.publish(p[1]))")
}
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Objek
1Class dan Object
Bekerja dengan FileMendefinisikan ClassMethod dan selfInitializerClass adalah ReferensiUlasan: Kartu Perpustakaan4Enkapsulasi
Kontrol AksesHanya Bisa Dibaca dari LuarMelindungi StateInitializer yang Bisa GagalRangkuman: Rekening Bank7Polimorfisme dan Generik
PolimorfismeKonversi TipeFungsi GenerikTipe GenerikRangkuman: Kalkulator Bentuk2Struct dan Tipe Nilai
StructSemantik NilaiMethod yang Mengubah NilaiStruct atau classRangkuman, Item Inventaris11Proyek: Manajemen Perpustakaan
Buku dan AnggotaPeminjaman BukuLatihan sendiri: Playground Swift