Observer Deseni
Coddy'nin GDScript Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 48 / 65.
Observer kalıbı, özne olan bir nesnenin birçok başka nesneye, yani gözlemcilere, bir şeyin gerçekleştiğini bildirmesini sağlar. Özne, gözlemcilerin bu bilgiyle ne yaptığını bilmez; yalnızca duyurur.
Elle yazıldığında, konu bir gözlemci dizisi tutar ve her birinde aynı yöntemi çağırır:
# health.gd
class_name Health
extends RefCounted
var observers: Array = []
var hp := 100
func add_observer(observer) -> void:
observers.append(observer)
func take_damage(amount: int) -> void:
hp -= amount
for observer in observers:
observer.on_hp_changed(hp)Godot'ta bu desen yerleşik olarak bulunur. Bir signal, öznenin duyurusudur ve her connect() bir gözlemci ekler; böylece diziye ve döngüye artık gerek kalmaz:
# health.gd
class_name Health
extends RefCounted
signal hp_changed(new_hp: int)
var hp := 100
func take_damage(amount: int) -> void:
hp -= amount
hp_changed.emit(hp)Gözlemci, parametreleri sinyalle eşleşen bir yönteme sahip herhangi bir nesnedir:
# health_bar.gd
class_name HealthBar
extends RefCounted
func on_hp_changed(new_hp: int) -> void:
print("Bar: ", new_hp, "/100")# damage_log.gd
class_name DamageLog
extends RefCounted
func on_hp_changed(new_hp: int) -> void:
if new_hp < 50:
print("Log: low health!")# main.gd
var health := Health.new()
var bar := HealthBar.new()
var damage_log := DamageLog.new()
health.hp_changed.connect(bar.on_hp_changed)
health.hp_changed.connect(damage_log.on_hp_changed)
health.take_damage(70)Bar: 30/100
Log: low health!Health bir çubuğun ya da günlüğün varlığından haberdar değildir. health.gd dosyasında tek bir değişiklik yapmadan bir ses efekti veya başarı da dinleyebilir.
Gözlemcilerin çalışmasını sağlayan üç kural vardır:
- Aynı yöntemi iki kez bağlamak hatadır. Bu durumun yaşanabileceği yerde, önce
hp_changed.is_connected(bar.on_hp_changed)ile kontrol et.disconnect()bir gözlemciyi kaldırır ve bağlı olmayan bir gözlemcinin bağlantısını kesmek de hatadır. - Bir bağlantı, gözlemcinin bellekte kalmasını sağlamaz. Gözlemciyi bir değişkende veya dizide tut:
connect()çağrısının içinde oluşturulan bir nesne hemen bellekten silinir ve sinyali hiçbir zaman duymaz. - Gözlemcilerin yöntemlerini bağla. Konuyu kullanan ve konunun kendi sinyaline bağlanan bir lambda, konunun sonsuza dek bellekte kalmasına neden olur; Godot bunu oyun kapandığında bellek sızıntısı olarak bildirir.
Görev
OrtaBir sinyalle ekranlarına bildirim gönderen bir hava istasyonu oluşturun.
weather_station.gd dosyasında:
temperature_changed(value: float)sinyalini tanımlayın.attach(display), ekranınon_temperature_changedyöntemine bağlanır. Zaten bağlı olan bir ekranı eklemek hiçbir şey yapmaz.detach(display)ekranın bağlantısını keser. Bağlı olmayan bir ekranın bağlantısını kesmek hiçbir şey yapmaz.set_temperature(value), değeritemperatureiçine kaydeder ve sinyali bu değerle yayar.
weather_display.gd dosyasında on_temperature_changed(value), ekran adını ve değeri bir ondalık basamakla yazdırır; örneğin Phone: 21.5 C.
Sağlanan kod, ekran adlarını tek satırda, ardından kaç komut geleceğini ve her satırda bir komut okuyup işler: attach NAME, detach NAME veya temp VALUE. Sonunda son sıcaklığı yazdırır. Phone Tablet adları ve attach Phone, attach Tablet, temp 21.5, detach Phone, temp 19 komutları için çıktı şöyledir:
Phone: 21.5 C
Tablet: 21.5 C
Tablet: 19.0 C
Final temperature: 19.0Kodunuzu weather_station.gd ve weather_display.gd dosyalarına yazın. main.gd, sağlanan giriş/çıkış kodunu içerir ve düzenlenemez.
Kendin dene
extends Node
func _ready():
# Sağlanan girdi/çıktı kodu: olduğu gibi bırakın
var station := WeatherStation.new()
var displays := {}
for display_name in OS.read_string_from_stdin().split(" "):
displays[display_name] = WeatherDisplay.new(display_name)
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ")
match parts[0]:
"attach":
station.attach(displays[parts[1]])
"detach":
station.detach(displays[parts[1]])
"temp":
station.set_temperature(float(parts[1]))
print("Final temperature: %.1f" % station.temperature)
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
1Nesne Yönelimli Programlamanın Temelleri
Harici DosyalarNesne Yönelimli Programlamaya GirişSınıflar ve Nesnelerself Anahtar KelimesiMetotlarÖzelliklerKurucu (_init)Tekrar - Basit Hesap Makinesi4Çok Biçimlilik
Metot Ezme Konusuna Yeniden BakışÖrdek TiplemesiSoyut Sınıflar ve MetotlarArayüz TasarımıÖzet - Şekil Hesaplayıcı7Sinyaller
Sinyal Nedir?Tanımlama ve Sinyal GöndermeSinyallere BağlanmaArgümanlı SinyallerTekrar - Sağlık Sistemi10Tasarım Kalıpları 2. Bölüm
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıBileşik Kalıp2Sınıf Özellikleri
Örnek ve Statik DeğişkenlerStatik FonksiyonlarÖzellik AyarlayıcılarıÖzellik AlıcılarıGeleneksel Olarak ÖzelTekrar - Banka Hesabı Yöneticisi5Kapsülleme
Public ve Private ÜyelerSetter'larla DoğrulamaBilgi GizlemeSalt Okunur ÖzelliklerTekrar - Öğrenci Kayıt Sistemi3Kalıtım
Temel Kalıtımsuper Anahtar SözcüğüMetot Geçersiz KılmaKalıtım Zincirleriis ile Tür KontrolleriTekrar: Çalışan Hiyerarşisi9Tasarım Desenleri Bölüm 1
Tasarım Desenlerine GirişSingleton DeseniFactory DeseniObserver DeseniStrategy DeseniKendi başına pratik yap: Online GDScript derleyicisi