الـ Observer Pattern معناه ببساطة:
عندك كائن بيحصل عنده حدث معين، وكائنات تانية مهتمة تعرف لما الحدث ده يحصل.
الكائنات المهتمة دي بتعمل subscribe، ولما الحدث يحصل، الكائن الأساسي يبعت لهم notification تلقائي.
زي YouTube:
- أنت عملت subscribe لقناة
- القناة نزلت فيديو جديد
- يوصلك notification
أنت هنا Observer، والقناة هي Subject (أو Observable).
بدل ما كل شوية تسأل:
- هل في فيديو جديد؟
- هل في فيديو جديد؟
- هل في فيديو جديد؟
تقول:
- لما يحصل فيديو جديد، بلغني.
وده أنظف وأكفأ.
بدون Observer غالبا بنقع في:
- Polling مستمر
- Coupling عالي بين المكونات
- كود متكرر وصعب الصيانة
مثال سيئ:
setInterval(() => {
checkIfUserChanged();
}, 1000);بدل السؤال المستمر، الأفضل استقبال التغيير وقت ما يحصل.
نعمل interface للمشتركين:
interface Observer<T> {
update(data: T): void;
}ونعمل Subject يدير الاشتراكات:
interface Subject<T> {
subscribe(observer: Observer<T>): void;
unsubscribe(observer: Observer<T>): void;
notify(data: T): void;
}مثال بسيط (YouTube Channel):
class YouTubeChannel implements Subject<string> {
private subscribers: Observer<string>[] = [];
subscribe(observer: Observer<string>): void {
this.subscribers.push(observer);
}
unsubscribe(observer: Observer<string>): void {
this.subscribers = this.subscribers.filter(s => s !== observer);
}
notify(videoTitle: string): void {
this.subscribers.forEach(s => s.update(videoTitle));
}
uploadVideo(title: string): void {
console.log(`New video uploaded: ${title}`);
this.notify(title);
}
}class Subscriber implements Observer<string> {
constructor(private name: string) {}
update(videoTitle: string): void {
console.log(`${this.name} got notification: ${videoTitle}`);
}
}
const channel = new YouTubeChannel();
const ahmed = new Subscriber("Ahmed");
const sara = new Subscriber("Sara");
channel.subscribe(ahmed);
channel.subscribe(sara);
channel.uploadVideo("Observer Pattern Explained");الناتج:
New video uploaded: Observer Pattern Explained
Ahmed got notification: Observer Pattern Explained
Sara got notification: Observer Pattern Explained
ممتاز في منطق:
- لما يحصل كذا، اعمل كذا
أمثلة عملية:
- لما user يعمل login، حدث UI
- لما cart يتغير، حدث السعر
- لما backend يرجع error، اعرض notification
- لما form value يتغير، نفذ validation
- لما socket message توصل، حدث الشاشة
أنت بتستخدم Observer كتير جدا حتى لو مش بتسميه كده:
this.userService.user$.subscribe(user => {
this.user = user;
});هنا:
user$هو Observable- الـ component هو Observer
مثال تاني:
this.form.valueChanges.subscribe(value => {
console.log(value);
});- تنبيه تلقائي: الـ subscribers يعرفوا فورا وقت الحدث.
- تنظيم أفضل: كل جزء يسمع فقط للأحداث اللي تهمه.
- أداء أفضل: بدل polling المستمر.
- فصل المسؤوليات: الـ Subject لا يعرف تفاصيل تنفيذ الـ Observer.
لو زاد بشكل مبالغ فيه ممكن تدخل في Event Callback Hell.
مثال سيئ:
user$.subscribe(() => {
settings$.subscribe(() => {
permissions$.subscribe(() => {
notifications$.subscribe(() => {
console.log("Too much nesting");
});
});
});
});في RxJS استخدم operators أنضف مثل:
combineLatestswitchMapmergeMaptakeUntilDestroyed
استخدمه لما يكون عندك events أو state changes وعايز أجزاء أخرى تتحدث تلقائيا.
أمثلة مناسبة:
- notifications
- form value changes
- route changes
- auth state
- cart updates
- websocket messages
- theme/language changes
لو العملية بسيطة ومباشرة:
const total = price * quantity;مفيش داعي تزود تعقيد.
- Strategy: تختار طريقة التنفيذ
- Observer: تسمع للحدث وتتفاعل لما يحصل
مثال:
- Strategy: الدفع كارت أو PayPal
- Observer: لما الدفع ينجح، ابعت email وحدث UI وسجل analytics
- Facade: يبسط التعامل مع نظام معقد
- Observer: يربط أجزاء متعددة بالأحداث والتغييرات
الـ Observer Pattern ممتاز لما يكون عندك:
- events
- state changes
- async updates
- UI reactions
القاعدة السهلة:
لو عندك جملة "لما يحصل كذا، بلّغ المهتمين" فكر في Observer.
classDiagram
class Observer~T~ {
<<interface>>
+update(data: T) void
}
class Subject~T~ {
<<interface>>
+subscribe(observer: Observer~T~) void
+unsubscribe(observer: Observer~T~) void
+notify(data: T) void
}
class YouTubeChannel {
-subscribers: Observer~string~[]
+subscribe(observer: Observer~string~) void
+unsubscribe(observer: Observer~string~) void
+notify(data: string) void
+uploadVideo(title: string) void
}
class Subscriber {
-name: string
+update(videoTitle: string) void
}
Subject <|.. YouTubeChannel
Observer <|.. Subscriber
YouTubeChannel --> Observer : notifies