۱. چیستی الگوی مشاهده‌گر (Observer Pattern)

الگوی مشاهده‌گر یک الگوی طراحی رفتاری است که برای برقراری یک به چند وابستگی بین اشیاء استفاده می‌شود. به طور خاص، وقتی یک شیء (معروف به موضوع یا قابل‌مشاهده) تغییر می‌کند، تمام وابستگی‌های خود (مشاهده‌گرها) مطلع و به‌طور خودکار به‌روزرسانی می‌شوند. این الگو اجازه می‌دهد که اشیاء موضوع و مشاهده‌گرها به‌صورت گشوده (loose coupling) با یکدیگر ارتباط برقرار کنند و از این‌طریق جداسازی و انعطاف‌پذیری بین اشیاء را فراهم می‌کند.

۲. ویژگی‌ها و مزایای الگوی مشاهده‌گر

الگوی مشاهده‌گر دارای ویژگی‌ها و مزایای زیر است:

  • اتصال گشوده بین اشیاء موضوع و مشاهده‌گرها، به‌طوری که موضوع نیازی به دانستن جزئیات اجرایی خاص مشاهده‌گرها ندارد.
  • اضافه و حذف پویا مشاهده‌گرها، باعث انعطاف‌پذیری بیشتر سیستم می‌شود.
  • پیروی از اصل باز و بسته بین اشیاء موضوع و مشاهده‌گرها، که گسترش و قابلیت استفاده مستقل را فراهم می‌کند.
  • برقراری یک به چند وابستگی، به‌طوری که یک موضوع می‌تواند چندین مشاهده‌گر داشته باشد.

۳. نمونه‌های کاربردی از الگوی مشاهده‌گر

الگوی مشاهده‌گر کاربردهای عملی بسیاری در زندگی واقعی دارد، مانند:

  • مکانیزم پردازش رویداد در رابط‌های گرافیکی کاربری، مانند پردازش اقدامات هنگام کلیک کردن روی یک دکمه.
  • فشار نقلیه‌های بازار سهام به صورت زمان واقعی.
  • اطلاع‌رسانی فعالیت‌های تبلیغاتی در پلتفرم‌های تجارت الکترونیک.

۴. پیاده‌سازی الگوی مشاهده‌گر در زبان برنامه‌نویسی گولانگ (Golang)

۴.۱ نمودار کلاس UML

الگوی مشاهده‌گر در گولانگ

۴.۲ معرفی نمونه

در این نمونه، ما یک موضوع (Subject) و دو مشاهده‌گر (ObserverA و ObserverB) داریم. موضوع قادر به ثبت، لغو ثبت و آگاه‌سازی مشاهده‌گرها است.

۴.۳ مراحل پیاده‌سازی

۴.۳.۱ ایجاد رابط موضوع و کلاس موضوع محاسبه‌شده

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()
    }
}

۴.۳.۲ ایجاد رابط گوش‌کننده و کلاس‌های گوش‌کننده محاسبه‌شده

type Observer interface {
    Update()
}

type ConcreteObserverA struct {}

func (observer *ConcreteObserverA) Update() {
    fmt.Println("مشاهده‌گر A آگاه‌سازی شد.")
}

type ConcreteObserverB struct {}

func (observer *ConcreteObserverB) Update() {
    fmt.Println("مشاهده‌گر B آگاه‌سازی شد.")
}

۴.۴ نمونه کد دمو

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 دوباره آگاه‌سازی شد.