1. รูปแบบการทำงานของ Observer Pattern

Observer Pattern เป็นรูปแบบการออกแบบที่ใช้สำหรับการสร้างความขึ้นอยู่หลายต่อหลายระหว่างอ็อบเจ็กต์ โดยเฉพาะเมื่อออบเจ็กต์ (ที่เรียกว่าเซอร์เวอร์หรือตัวสังเกต) เปลี่ยนแปลง โดยที่ทุกรายการอันเป็นลูกของมัน (ที่เรียกว่าผู้สังเกต) จะได้รับการแจ้งเตือนและอัปเดตโดยอัตโนมัติ รูปแบบนี้ช่วยให้การเชื่อมโยงระหว่างอเอ็กต์และผู้สังเกตเป็นระบบผันผวน จึงทำให้การเชื่อมโยงและความยืดหยุ่นระหว่างออบเจ็กต์เป็นไปอย่างหลีกเลี่ยงและยืดหยุ่น

2. ลักษณะและข้อดีของ Observer Pattern

Observer Pattern มีลักษณะและข้อดีต่อไปนี้:

  • การเชื่อมโยงผันผวนระหว่างออบเจ็กต์และผู้สังเกตโดยที่ออบเจ็กต์ไม่จำเป็นต้องทราบรายละเอียดการสร้างสรรค์ของผู้สังเกต
  • การเพิ่มและลบผู้สังเกตอย่างไดนามิกทำให้ระบบยืดหยุ่นมากขึ้น
  • ปฏิบัติต่อหลักเปิด-ปิดระหว่างออบเจ็กต์และผู้สังเกต ทำให้สามารถเพิ่มส่วนขยายและการนำกลับซ้ำแยำได้อย่างอิสระ
  • สามารถสร้างความขึ้นอยู่หลายต่อหลายระหว่างออบเจ็กต์และผู้สังเกตได้ที่เซอร์เวอร์หนึ่ง

3. ตัวอย่างการประยุกต์ใช้งานของ Observer Pattern

Observer Pattern มีการประยุกต์ใช้ทางปฏิบัติมากมายในชีวิตจริง เช่น:

  • กลไกการจัดการเหตุการณ์ในอินเตอร์เฟซกราฟิกสเข็นทีฟมีเหตุระงับระบบของปุ่นเมื้อทำการคลิก
  • การเผยแพร่ราคาหุ้นแบบเรียลไทม์
  • การแจ้งเตือนกิจกรรมโปรโมชั่นในแพลตฟอร์มอีคอมเมิรซ

4. การประยุกต์ใช้งานของ Observer Pattern ใน Golang

4.1 แผนภาพคลาส UML

รูปแบบการอ่านข่าว Observer ใน Golang

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 ได้รับการแจ้งเตือนอีกครั้ง