1. รูปแบบการทำงานของ Observer Pattern
Observer Pattern เป็นรูปแบบการออกแบบที่ใช้สำหรับการสร้างความขึ้นอยู่หลายต่อหลายระหว่างอ็อบเจ็กต์ โดยเฉพาะเมื่อออบเจ็กต์ (ที่เรียกว่าเซอร์เวอร์หรือตัวสังเกต) เปลี่ยนแปลง โดยที่ทุกรายการอันเป็นลูกของมัน (ที่เรียกว่าผู้สังเกต) จะได้รับการแจ้งเตือนและอัปเดตโดยอัตโนมัติ รูปแบบนี้ช่วยให้การเชื่อมโยงระหว่างอเอ็กต์และผู้สังเกตเป็นระบบผันผวน จึงทำให้การเชื่อมโยงและความยืดหยุ่นระหว่างออบเจ็กต์เป็นไปอย่างหลีกเลี่ยงและยืดหยุ่น
2. ลักษณะและข้อดีของ Observer Pattern
Observer Pattern มีลักษณะและข้อดีต่อไปนี้:
- การเชื่อมโยงผันผวนระหว่างออบเจ็กต์และผู้สังเกตโดยที่ออบเจ็กต์ไม่จำเป็นต้องทราบรายละเอียดการสร้างสรรค์ของผู้สังเกต
- การเพิ่มและลบผู้สังเกตอย่างไดนามิกทำให้ระบบยืดหยุ่นมากขึ้น
- ปฏิบัติต่อหลักเปิด-ปิดระหว่างออบเจ็กต์และผู้สังเกต ทำให้สามารถเพิ่มส่วนขยายและการนำกลับซ้ำแยำได้อย่างอิสระ
- สามารถสร้างความขึ้นอยู่หลายต่อหลายระหว่างออบเจ็กต์และผู้สังเกตได้ที่เซอร์เวอร์หนึ่ง
3. ตัวอย่างการประยุกต์ใช้งานของ Observer Pattern
Observer Pattern มีการประยุกต์ใช้ทางปฏิบัติมากมายในชีวิตจริง เช่น:
- กลไกการจัดการเหตุการณ์ในอินเตอร์เฟซกราฟิกสเข็นทีฟมีเหตุระงับระบบของปุ่นเมื้อทำการคลิก
- การเผยแพร่ราคาหุ้นแบบเรียลไทม์
- การแจ้งเตือนกิจกรรมโปรโมชั่นในแพลตฟอร์มอีคอมเมิรซ
4. การประยุกต์ใช้งานของ Observer Pattern ใน Golang
4.1 แผนภาพคลาส UML
4.2 ข้อมูลเบื้องต้นของตัวอย่าง
ในตัวอย่างนี้ เรามีเซอร์เวอร์ (Subject) และผู้สังเกตสองรายการ (ObserverA และ ObserverB) เซอร์เวอร์สามารถลงทะเบียน ยกเลิกการลงทะเบียน และแจ้งเตือนผู้สังเกต
4.3 ขั้นตอนการปฏิบัติ
4.3.1 สร้างอินเตอร์เฟสเซอร์และคลาสเบื้องต้น
type Subject interface {
RegisterObserver(observer Observer)
RemoveObserver(observer Observer)
NotifyObservers()
}
type ConcreteSubject struct {
observers []Observer
}
// ลงทะเบียนออบเจ็กต์ผู้ติดตาม
func (subject *ConcreteSubject) RegisterObserver(observer Observer) {
subject.observers = append(subject.observers, observer)
}
// ยกเลิกออบเจ็กต์ผู้ติดตาม
func (subject *ConcreteSubject) RemoveObserver(observer Observer) {
for i, obs := range subject.observers {
if obs == observer {
subject.observers = append(subject.observers[:i], subject.observers[i+1:]...)
break
}
}
}
// เรียกเรื่องแจ้งเตือน
func (subject *ConcreteSubject) NotifyObservers() {
for _, observer := range subject.observers {
observer.Update()
}
}
4.3.2 สร้างอินเตอร์เฟสผู้สังเกตและคลาสผู้สังเกตเบื้องต้น
type Observer interface {
Update()
}
type ConcreteObserverA struct {}
func (observer *ConcreteObserverA) Update() {
fmt.Println("ผู้ติดตาม A ได้รับการแจ้งเตือน.")
}
type ConcreteObserverB struct {}
func (observer *ConcreteObserverB) Update() {
fmt.Println("ผู้ติดตาม B ได้รับการแจ้งเตือน.")
}
4.4 การรันตัวอย่างโค้ด
func main() {
subject := &ConcreteSubject{}
observerA := &ConcreteObserverA{}
observerB := &ConcreteObserverB{}
subject.RegisterObserver(observerA)
subject.RegisterObserver(observerB)
subject.NotifyObservers()
subject.RemoveObserver(observerA)
subject.NotifyObservers()
}
ผลลัพธ์:
ผู้ติดตาม A ได้รับการแจ้งเตือน
ผู้ติดตาม B ได้รับการแจ้งเตือน
ผู้ติดตาม B ได้รับการแจ้งเตือน
โค้ดตัวอย่างข้างต้นสาธิตการประยุกต์ใช้รูปแบบการติดตามอย่างตัวตน โดยที่เซอร์เวอร์ (ConcreteSubject) ลงทะเบียนผู้ติดตามสองรายการ (ObserverA และ ObserverB) และจากนั้นแจ้งเตือนผู้ติดตามทั้งสองรายการ หลังจากนั้น ผู้ติดตาม A ถูกยกเลิกจากเซอร์เวอร์ และผู้ติดตาม B ได้รับการแจ้งเตือนอีกครั้ง