1. ما هو نمط المراقب (Observer Pattern)
نمط المراقب هو نمط تصميم سلوكي يستخدم لإقامة تبعية واحد-إلى-الكثير بين الكائنات. تحديداً، عندما يتغير كائن (الذي يُشار إليه بالموضوع أو المراقب)، يتم إخطار جميع تبعياته (التي تُشار إليها بالمراقبين) وتحديثها تلقائياً. يسمح هذا النمط بتقارن فضفاض بين المواضيع والمراقبين، مما يحقق فصلًا ومرونة بين الكائنات.
2. السمات والمزايا لنمط المراقب (Observer Pattern)
نمط المراقب له السمات والمزايا التالية:
- ارتباط فضفاض بين المواضيع والمراقبين، حيث لا يحتاج الموضوع إلى معرفة تفاصيل التنفيذ المحددة للمراقبين.
- إضافة وإزالة ديناميكية للمراقبين، مما يجعل النظام أكثر مرونة.
- يتبع مبدأ الافتح-أغلق بين المواضيع والمراقبين، مما يمكن من تمديد مستقل وإعادة استخدامه.
- يمكن إنشاء علاقة تبعية واحد-إلى-الكثير، حيث يمكن للموضوع أن يمتلك عدة مراقبين.
3. أمثلة للتطبيقات العملية لنمط المراقب (Observer Pattern)
نمط المراقب له العديد من التطبيقات العملية في الحياة الواقعية، مثل:
- آلية التعامل مع الأحداث في واجهات GUI، مثل التعامل مع الإجراءات عند النقر فوق زر ما.
- تحديثات سوق الأسهم في الوقت الحقيقي.
- الإخطار بالأنشطة الترويجية على منصات التجارة الإلكترونية.
4. تنفيذ نمط المراقب في 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 المتبقي مرة أخرى.