Pola Observer
Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan GDScript di Coddy. Pelajaran 48 dari 65.
Pola Observer memungkinkan satu object, yaitu subject, memberi tahu banyak object lain, yaitu observer, bahwa sesuatu telah terjadi. Subject tidak mengetahui apa yang dilakukan observer dengan informasi tersebut; subject hanya mengumumkannya.
Jika ditulis secara manual, subjek menyimpan array observer dan memanggil method yang sama pada setiap observer:
# 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 sudah memiliki pola ini. Sinyal adalah pengumuman dari subjek, dan setiap connect() menambahkan pengamat, sehingga array dan perulangan tidak lagi diperlukan:
# 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)Observer adalah object apa pun yang memiliki method dengan parameter yang cocok dengan sinyal:
# 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 tidak tahu bahwa bar atau log ada. Efek suara atau pencapaian juga bisa mendengarkan, tanpa mengubah health.gd sedikit pun.
Tiga aturan menjaga pengamat tetap berfungsi:
- Menghubungkan method yang sama dua kali akan menyebabkan error. Jika hal itu mungkin terjadi, periksa terlebih dahulu dengan
hp_changed.is_connected(bar.on_hp_changed).disconnect()menghapus pengamat, dan memutuskan koneksi yang belum terhubung juga menyebabkan error. - Koneksi tidak membuat pengamat tetap hidup. Simpan pengamat dalam variabel atau array: object yang dibuat di dalam pemanggilan
connect()langsung dibebaskan dan tidak akan pernah menerima sinyal. - Hubungkan method milik pengamat. Lambda yang menggunakan subjek dan terhubung ke sinyal milik subjek sendiri akan membuat subjek tetap hidup selamanya, yang dilaporkan Godot sebagai kebocoran saat game ditutup.
Tantangan
SedangBuat stasiun cuaca yang memberi tahu display-nya dengan sinyal.
Di weather_station.gd:
- Deklarasikan sinyal
temperature_changed(value: float). attach(display)menghubungkan display ke methodon_temperature_changed. Memasang display yang sudah terpasang tidak melakukan apa pun.detach(display)memutuskan hubungannya. Melepas display yang belum terpasang tidak melakukan apa pun.set_temperature(value)menyimpan nilai ditemperaturedan memancarkan sinyal dengan nilai tersebut.
Di weather_display.gd, on_temperature_changed(value) mencetak nama display dan nilainya dengan satu angka desimal, seperti Phone: 21.5 C.
Kode yang disediakan membaca nama display dalam satu baris, jumlah perintah berikutnya, lalu satu perintah per baris: attach NAME, detach NAME, atau temp VALUE. Pada akhirnya, kode mencetak suhu terakhir. Untuk nama Phone Tablet dan perintah attach Phone, attach Tablet, temp 21.5, detach Phone, temp 19, output-nya adalah:
Phone: 21.5 C
Tablet: 21.5 C
Tablet: 19.0 C
Final temperature: 19.0Tulis kodemu di weather_station.gd dan weather_display.gd. main.gd berisi kode input/output yang disediakan dan tidak dapat diedit.
Coba sendiri
extends Node
func _ready():
# Kode input/output yang disediakan: biarkan apa adanya
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)
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Objek
1Dasar-Dasar OOP
File EksternalPengantar OOPclass dan objectKata Kunci selfmethodpropertyKonstruktor (_init)Ringkasan: Kalkulator Sederhana4Polimorfisme
Method Overriding Sekali LagiDuck TypingKelas Abstrak dan MethodDesain InterfaceRingkasan: Kalkulator Bentuk7Sinyal
Apa itu Sinyal?Mendeklarasikan dan MemancarkanMenghubungkan ke SinyalSinyal dengan ArgumenRangkuman, Sistem Kesehatan10Pola Desain Bagian 2
Pola CommandPola AdapterPola DecoratorPola Template MethodPola StatePola Composite2Property class
Variabel instance vs. variabel statisFungsi statisSetter propertyGetter propertyPrivat berdasarkan konvensiRangkuman: Pengelola Rekening Bank5Enkapsulasi
Member Publik dan PrivatValidasi dengan SetterPenyembunyian InformasiProperty Hanya-BacaRingkasan: Sistem Catatan Siswa8Konsep OOP Lanjutan
Komposisi vs PewarisanInner ClassNode sebagai KomponenRefCounted vs NodeEnum dalam Class11Proyek: Manajemen Perpustakaan
Gambaran Umum Proyekclass Buku dan PenggunaLatihan sendiri: Compiler GDScript online