---
title: "المراقب"
type: "design-pattern"
slug: "observer"
url: "http://localhost:3000/ar/design-patterns/observer.md"
category: "الأنماط السلوكية"
description: "المراقب هو نمط تصميم سلوكي يتيح لك تحديد آلية اشتراك لإخطار كائنات متعددة بأي أحداث تحدث للكائن الذي يراقبونه."
languages: ["java", "csharp", "cpp", "go", "php", "python", "ruby", "rust", "swift", "typescript"]
---
# المراقب

> المراقب هو نمط تصميم سلوكي يتيح لك تحديد آلية اشتراك لإخطار كائنات متعددة بأي أحداث تحدث للكائن الذي يراقبونه.

## Intent

**المراقب** هو نمط تصميم سلوكي يتيح لك تحديد آلية اشتراك لإخطار كائنات متعددة بأي أحداث تحدث للكائن الذي يراقبونه.

## Problem

تخيل أن لديك نوعين من الكائنات: `Customer` و`Store`. العميل مهتم جداً بعلامة تجارية معينة من المنتجات (لنقل إنها طراز جديد من iPhone) والتي يُفترض أن تتوفر في المتجر قريباً.

يمكن للعميل زيارة المتجر كل يوم للتحقق من توفر المنتج. لكن طالما أن المنتج لا يزال في الطريق، فمعظم هذه الزيارات ستكون بلا جدوى.

زيارة المتجر مقابل إرسال البريد العشوائي

من ناحية أخرى، يمكن للمتجر إرسال كميات ضخمة من الرسائل الإلكترونية (التي قد تُعدّ بريداً عشوائياً) لجميع العملاء في كل مرة يتوفر فيها منتج جديد. سيوفر هذا على بعض العملاء رحلات لا نهاية لها إلى المتجر. في الوقت ذاته، سيُزعج العملاء الآخرين الذين لا يهتمون بالمنتجات الجديدة.

يبدو أننا أمام تعارض. إما أن يُضيع العميل وقته في التحقق من توفر المنتج، أو أن يُهدر المتجر موارده في إخطار العملاء غير المعنيين.

## Solution

يُطلق على الكائن الذي يمتلك حالة مثيرة للاهتمام في الغالب اسم _الموضوع_، ولكن بما أنه سيُخطر الكائنات الأخرى أيضاً بالتغييرات في حالته، سنسميه _الناشر_. أما جميع الكائنات الأخرى التي تريد تتبع التغييرات في حالة الناشر فتُسمى _المشتركين_.

يقترح نمط المراقب إضافة آلية اشتراك إلى فئة الناشر، حتى تتمكن الكائنات الفردية من الاشتراك في تدفق الأحداث القادمة من ذلك الناشر أو إلغاء اشتراكها. لا داعي للقلق! الأمر ليس بهذا التعقيد. في الواقع، تتألف هذه الآلية من: 1) حقل مصفوفة لتخزين قائمة من المراجع لكائنات المشترك، و2) عدة توابع عامة تتيح إضافة المشتركين إلى القائمة وإزالتهم منها.

تتيح آلية الاشتراك للكائنات الفردية الاشتراك في إشعارات الأحداث.

الآن، في كل مرة يحدث فيها حدث مهم للناشر، يمر على قائمة مشتركيه ويستدعي تابع الإخطار المحدد على كائناتهم.

قد تحتوي التطبيقات الحقيقية على عشرات الفئات المشتركة المختلفة المهتمة بتتبع أحداث فئة الناشر ذاتها. لن تريد ربط الناشر بجميع تلك الفئات. علاوة على ذلك، قد لا تعلم ببعضها مسبقاً إذا كانت فئة الناشر مخصصة للاستخدام من قِبل أشخاص آخرين.

لهذا السبب من الضروري أن يُنفِّذ جميع المشتركين الواجهة ذاتها وأن يتواصل الناشر معهم فقط عبر تلك الواجهة. يجب أن تُعلن هذه الواجهة عن تابع الإخطار مع مجموعة من المعاملات التي يمكن للناشر استخدامها لتمرير بعض البيانات السياقية مع الإخطار.

يُخطر الناشر المشتركين باستدعاء تابع الإخطار المحدد على كائناتهم.

إذا كان تطبيقك يحتوي على عدة أنواع مختلفة من الناشرين وأردت جعل مشتركيك متوافقين معها جميعاً، فيمكنك المضي أبعد من ذلك وجعل جميع الناشرين يتبعون الواجهة ذاتها. لن تحتاج هذه الواجهة إلا إلى وصف عدد قليل من توابع الاشتراك. ستتيح الواجهة للمشتركين مراقبة حالات الناشرين دون الارتباط بفئاتهم الملموسة.

## Structure

1. يُصدر **الناشر** أحداثاً تهم الكائنات الأخرى. تحدث هذه الأحداث عندما يغير الناشر حالته أو ينفذ بعض السلوكيات. يحتوي الناشرون على بنية تحتية للاشتراك تتيح للمشتركين الجدد الانضمام وللمشتركين الحاليين مغادرة القائمة.
2. عند وقوع حدث جديد، يمر الناشر على قائمة الاشتراك ويستدعي تابع الإخطار المُعلَن عنه في واجهة المشترك على كل كائن مشترك.
3. تُعلن واجهة **المشترك** عن واجهة الإخطار. في معظم الحالات، تتألف من تابع `update` واحد. قد يحتوي التابع على عدة معاملات تتيح للناشر تمرير بعض تفاصيل الحدث مع التحديث.
4. يؤدي **المشتركون الملموسون** بعض الإجراءات استجابةً للإخطارات الصادرة عن الناشر. يجب أن تنفذ جميع هذه الفئات الواجهة ذاتها حتى لا يرتبط الناشر بالفئات الملموسة.
5. عادةً ما يحتاج المشتركون إلى بعض المعلومات السياقية للتعامل مع التحديث بشكل صحيح. لهذا السبب، كثيراً ما يمرر الناشرون بعض بيانات السياق كوسائط لتابع الإخطار. يمكن للناشر تمرير نفسه كوسيطة، مما يسمح للمشترك بجلب أي بيانات مطلوبة مباشرة.
6. يُنشئ **العميل** كائنات الناشر والمشترك بشكل منفصل ثم يسجل المشتركين لتحديثات الناشر.

## Pseudocode

في هذا المثال، يتيح نمط **المراقب** لكائن محرر النصوص إخطار كائنات الخدمة الأخرى بالتغييرات في حالته.

إخطار الكائنات بالأحداث التي تحدث لكائنات أخرى.

تُجمَّع قائمة المشتركين بشكل ديناميكي: يمكن للكائنات البدء في الاستماع إلى الإخطارات أو التوقف عنها في وقت التشغيل، وذلك تبعاً للسلوك المطلوب لتطبيقك.

في هذا التطبيق، لا تحتفظ فئة المحرر بقائمة الاشتراك بنفسها. تُفوِّض هذه المهمة إلى كائن مساعد خاص مخصص لذلك فقط. يمكنك ترقية ذلك الكائن ليعمل كموزع أحداث مركزي، مما يتيح لأي كائن العمل ناشراً.

إضافة مشتركين جدد إلى البرنامج لا تستلزم إجراء تغييرات على فئات الناشر الموجودة، طالما أنهم يعملون مع جميع المشتركين عبر الواجهة ذاتها.

// تتضمن فئة الناشر الأساسية شفرة إدارة الاشتراك
// وتوابع الإخطار.
class EventManager is
    private field listeners: hash map of event types and listeners

    method subscribe(eventType, listener) is
        listeners.add(eventType, listener)

    method unsubscribe(eventType, listener) is
        listeners.remove(eventType, listener)

    method notify(eventType, data) is
        foreach (listener in listeners.of(eventType)) do
            listener.update(data)

// يحتوي الناشر الملموس على منطق الأعمال الحقيقي الذي
// يهم بعض المشتركين. يمكننا اشتقاق هذه الفئة من
// الناشر الأساسي، لكن هذا ليس ممكناً دائماً في الواقع
// العملي لأن الناشر الملموس قد يكون بالفعل فئة فرعية.
// في هذه الحالة، يمكنك تصحيح منطق الاشتراك باستخدام
// التركيب، كما فعلنا هنا.
class Editor is
    public field events: EventManager
    private field file: File

    constructor Editor() is
        events = new EventManager()

    // يمكن لتوابع منطق الأعمال إخطار المشتركين بالتغييرات.
    method openFile(path) is
        this.file = new File(path)
        events.notify("open", file.name)

    method saveFile() is
        file.write()
        events.notify("save", file.name)

    // ...

// هذه هي واجهة المشترك. إذا كانت لغة البرمجة تدعم
// الأنواع الدالية، يمكنك استبدال تسلسل المشترك بأكمله
// بمجموعة من الدوال.
interface EventListener is
    method update(filename)

// يتفاعل المشتركون الملموسون مع التحديثات الصادرة عن الناشر
// المرتبطين به.
class LoggingListener implements EventListener is
    private field log: File
    private field message: string

    constructor LoggingListener(log_filename, message) is
        this.log = new File(log_filename)
        this.message = message

    method update(filename) is
        log.write(replace('%s',filename,message))

class EmailAlertsListener implements EventListener is
    private field email: string
    private field message: string

    constructor EmailAlertsListener(email, message) is
        this.email = email
        this.message = message

    method update(filename) is
        system.email(email, replace('%s',filename,message))

// يمكن للتطبيق تكوين الناشرين والمشتركين في وقت التشغيل.
class Application is
    method config() is
        editor = new Editor()

        logger = new LoggingListener(
            "/path/to/log.txt",
            "Someone has opened the file: %s")
        editor.events.subscribe("open", logger)

        emailAlerts = new EmailAlertsListener(
            "admin@example.com",
            "Someone has changed the file: %s")
        editor.events.subscribe("save", emailAlerts)

## Applicability

استخدم نمط المراقب عندما تستلزم التغييرات في حالة كائن ما تغيير كائنات أخرى، وكانت المجموعة الفعلية من الكائنات غير معروفة مسبقاً أو تتغير بشكل ديناميكي.

 كثيراً ما تواجه هذه المشكلة عند العمل مع فئات واجهة المستخدم الرسومية. على سبيل المثال، إذا أنشأت فئات أزرار مخصصة وأردت السماح للعملاء بربط شفرة مخصصة بأزرارك لتُنفَّذ في كل مرة يضغط فيها المستخدم على الزر.

يتيح نمط المراقب لأي كائن يُنفِّذ واجهة المشترك الاشتراك في إشعارات الأحداث في كائنات الناشر. يمكنك إضافة آلية الاشتراك إلى أزرارك، مما يتيح للعملاء ربط شفراتهم المخصصة عبر فئات مشترك مخصصة.

 استخدم النمط عندما يجب على بعض الكائنات في تطبيقك مراقبة كائنات أخرى، ولكن لفترة محدودة أو في حالات معينة فقط.

 قائمة الاشتراك ديناميكية، لذا يمكن للمشتركين الانضمام إلى القائمة أو مغادرتها في أي وقت يحتاجون إليه.

## How to Implement

1. راجع منطق أعمالك وحاول تقسيمه إلى جزأين: ستعمل الوظائف الأساسية المستقلة عن الشفرة الأخرى ناشراً؛ أما الباقي فسيتحول إلى مجموعة من فئات المشترك.
2. أعلن عن واجهة المشترك. في حدها الأدنى، يجب أن تُعلن عن تابع `update` واحد.
3. أعلن عن واجهة الناشر وصف زوجاً من التوابع لإضافة كائن مشترك إلى القائمة وإزالته منها. تذكر أن الناشرين يجب أن يعملوا مع المشتركين فقط عبر واجهة المشترك.
4. قرر أين ستضع قائمة الاشتراك الفعلية وتطبيق توابع الاشتراك. عادةً ما تبدو هذه الشفرة متشابهة لجميع أنواع الناشرين، لذا فالمكان الواضح لوضعها هو في فئة مجردة مشتقة مباشرة من واجهة الناشر. يمتد الناشرون الملموسون تلك الفئة، ويرثون سلوك الاشتراك.
ومع ذلك، إذا كنت تطبق النمط على تسلسل هرمي موجود من الفئات، فضع في اعتبارك نهجاً يعتمد على التركيب: ضع منطق الاشتراك في كائن منفصل، واجعل جميع الناشرين الفعليين يستخدمونه.
5. أنشئ فئات الناشر الملموسة. في كل مرة يحدث فيها شيء مهم داخل الناشر، يجب عليه إخطار جميع مشتركيه.
6. نفِّذ توابع إشعار التحديث في فئات المشترك الملموسة. سيحتاج معظم المشتركين إلى بعض بيانات السياق حول الحدث. يمكن تمريرها كوسيطة لتابع الإخطار.
لكن هناك خيار آخر. عند استقبال إخطار، يمكن للمشترك جلب أي بيانات مباشرة من الإخطار. في هذه الحالة، يجب على الناشر تمرير نفسه عبر تابع التحديث. الخيار الأقل مرونة هو ربط الناشر بالمشترك بشكل دائم عبر الباني.
7. يجب على العميل إنشاء جميع المشتركين الضروريين وتسجيلهم مع الناشرين المناسبين.

## Pros

* _مبدأ الفتح/الإغلاق_. يمكنك إدخال فئات مشترك جديدة دون الحاجة إلى تغيير شفرة الناشر (والعكس صحيح إذا كانت هناك واجهة ناشر).
* يمكنك تأسيس علاقات بين الكائنات في وقت التشغيل.

## Cons

* يُخطَر المشتركون بترتيب عشوائي.

## Relations with Other Patterns

* [سلسلة المسؤولية](/ar/design-patterns/chain-of-responsibility)، [الأمر](/ar/design-patterns/command)، [الوسيط](/ar/design-patterns/mediator) و[المراقب](/ar/design-patterns/observer) تعالج طرقاً مختلفة لتوصيل مُرسِلي الطلبات بمستقبليها:

  * _سلسلة المسؤولية_ تمرر الطلب بشكل متسلسل عبر سلسلة ديناميكية من المستقبلين المحتملين حتى يتعامل معه أحدهم.
  * _الأمر_ يُنشئ اتصالات أحادية الاتجاه بين المُرسِلين والمستقبلين.
  * _الوسيط_ يُزيل الاتصالات المباشرة بين المُرسِلين والمستقبلين، ويُجبرهم على التواصل بشكل غير مباشر عبر كائن وسيط.
  * _المراقب_ يتيح للمستقبلين الاشتراك الديناميكي في استقبال الطلبات أو إلغاء الاشتراك.
* الفرق بين [الوسيط](/ar/design-patterns/mediator) و[المراقب](/ar/design-patterns/observer) كثيراً ما يكون غامضاً. في معظم الحالات، يمكنك تطبيق أي من النمطين؛ لكن أحياناً يمكنك تطبيق كليهما في آنٍ واحد. دعنا نرى كيف يمكن تحقيق ذلك.
الهدف الأساسي لـ_الوسيط_ هو إزالة الاعتماديات المتبادلة بين مجموعة من مكونات النظام. بدلاً من ذلك، تصبح هذه المكونات معتمدة على كائن وسيط واحد. أما هدف _المراقب_ فهو إنشاء اتصالات أحادية الاتجاه وديناميكية بين الكائنات، حيث تعمل بعض الكائنات كمرؤوسين للآخرين.
ثمة تطبيق شائع لنمط _الوسيط_ يعتمد على _المراقب_. يؤدي كائن الوسيط دور الناشر، وتعمل المكونات كمشتركين يشتركون في أحداث الوسيط ويلغون اشتراكهم. عندما يُطبَّق _الوسيط_ بهذه الطريقة، قد يبدو مشابهاً جداً لـ_المراقب_.
عند الشك، تذكر أنه يمكنك تطبيق نمط الوسيط بطرق أخرى. على سبيل المثال، يمكنك ربط جميع المكونات بكائن الوسيط ذاته بشكل دائم. هذا التطبيق لن يشبه _المراقب_ لكنه سيظل مثيلاً لنمط الوسيط.
تخيل الآن برنامجاً أصبحت فيه جميع المكونات ناشرين، مما يتيح اتصالات ديناميكية فيما بينها. لن يكون هناك كائن وسيط مركزي، بل مجموعة موزعة من المراقبين.
## Relations

**Related patterns**

- [سلسلة المسؤوليات](/ar/design-patterns/chain-of-responsibility.md)
- [الأمر (Command)](/ar/design-patterns/command.md)
- [الوسيط](/ar/design-patterns/mediator.md)

## Code Examples

### java

```java
package refactoring_guru.observer.example.publisher;

import refactoring_guru.observer.example.listeners.EventListener;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class EventManager {
    Map<String, List<EventListener>> listeners = new HashMap<>();

    public EventManager(String... operations) {
        for (String operation : operations) {
            this.listeners.put(operation, new ArrayList<>());
        }
    }

    public void subscribe(String eventType, EventListener listener) {
        List<EventListener> users = listeners.get(eventType);
        users.add(listener);
    }

    public void unsubscribe(String eventType, EventListener listener) {
        List<EventListener> users = listeners.get(eventType);
        users.remove(listener);
    }

    public void notify(String eventType, File file) {
        List<EventListener> users = listeners.get(eventType);
        for (EventListener listener : users) {
            listener.update(eventType, file);
        }
    }
}

package refactoring_guru.observer.example.editor;

import refactoring_guru.observer.example.publisher.EventManager;

import java.io.File;

public class Editor {
    public EventManager events;
    private File file;

    public Editor() {
        this.events = new EventManager("open", "save");
    }

    public void openFile(String filePath) {
        this.file = new File(filePath);
        events.notify("open", file);
    }

    public void saveFile() throws Exception {
        if (this.file != null) {
            events.notify("save", file);
        } else {
            throw new Exception("Please open a file first.");
        }
    }
}

package refactoring_guru.observer.example.listeners;

import java.io.File;

public interface EventListener {
    void update(String eventType, File file);
}

package refactoring_guru.observer.example.listeners;

import java.io.File;

public class EmailNotificationListener implements EventListener {
    private String email;

    public EmailNotificationListener(String email) {
        this.email = email;
    }

    @Override
    public void update(String eventType, File file) {
        System.out.println("Email to " + email + ": Someone has performed " + eventType + " operation with the following file: " + file.getName());
    }
}

package refactoring_guru.observer.example.listeners;

import java.io.File;

public class LogOpenListener implements EventListener {
    private File log;

    public LogOpenListener(String fileName) {
        this.log = new File(fileName);
    }

    @Override
    public void update(String eventType, File file) {
        System.out.println("Save to log " + log + ": Someone has performed " + eventType + " operation with the following file: " + file.getName());
    }
}

package refactoring_guru.observer.example;

import refactoring_guru.observer.example.editor.Editor;
import refactoring_guru.observer.example.listeners.EmailNotificationListener;
import refactoring_guru.observer.example.listeners.LogOpenListener;

public class Demo {
    public static void main(String[] args) {
        Editor editor = new Editor();
        editor.events.subscribe("open", new LogOpenListener("/path/to/log/file.txt"));
        editor.events.subscribe("save", new EmailNotificationListener("admin@example.com"));

        try {
            editor.openFile("test.txt");
            editor.saveFile();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Save to log \path\to\log\file.txt: Someone has performed open operation with the following file: test.txt
Email to admin@example.com: Someone has performed save operation with the following file: test.txt
```

### csharp

```csharp
using System;
using System.Collections.Generic;
using System.Threading;

namespace RefactoringGuru.DesignPatterns.Observer.Conceptual
{
    public interface IObserver
    {
        // استقبال تحديث من الموضوع
        void Update(ISubject subject);
    }

    public interface ISubject
    {
        // ربط مراقب بالموضوع.
        void Attach(IObserver observer);

        // فصل مراقب من الموضوع.
        void Detach(IObserver observer);

        // إخطار جميع المراقبين بحدث.
        void Notify();
    }

    // يمتلك الموضوع حالة مهمة ويُخطر المراقبين عند
    // تغيُّر الحالة.
    public class Subject : ISubject
    {
        // من أجل التبسيط، تُخزَّن حالة الموضوع الضرورية لجميع
        // المشتركين في هذا المتغير.
        public int State { get; set; } = -0;

        // قائمة المشتركين. في الواقع العملي، يمكن تخزين قائمة المشتركين
        // بصورة أشمل (مصنفةً حسب نوع الحدث، وما إلى ذلك).
        private List<IObserver> _observers = new List<IObserver>();

        // توابع إدارة الاشتراك.
        public void Attach(IObserver observer)
        {
            Console.WriteLine("Subject: Attached an observer.");
            this._observers.Add(observer);
        }

        public void Detach(IObserver observer)
        {
            this._observers.Remove(observer);
            Console.WriteLine("Subject: Detached an observer.");
        }

        // تشغيل تحديث في كل مشترك.
        public void Notify()
        {
            Console.WriteLine("Subject: Notifying observers...");

            foreach (var observer in _observers)
            {
                observer.Update(this);
            }
        }

        // عادةً ما يمثل منطق الاشتراك جزءاً بسيطاً مما يمكن للموضوع
        // فعله فعلياً. يحتوي الموضوع عادةً على منطق أعمال مهم،
        // يُشغِّل تابع إخطار كلما كان شيء مهم على وشك الحدوث (أو بعده).
        public void SomeBusinessLogic()
        {
            Console.WriteLine("\nSubject: I'm doing something important.");
            this.State = new Random().Next(0, 10);

            Thread.Sleep(15);

            Console.WriteLine("Subject: My state has just changed to: " + this.State);
            this.Notify();
        }
    }

    // يتفاعل المراقبون الملموسون مع التحديثات الصادرة عن الموضوع
    // الذي ارتبطوا به.
    class ConcreteObserverA : IObserver
    {
        public void Update(ISubject subject)
        {            
            if ((subject as Subject).State < 3)
            {
                Console.WriteLine("ConcreteObserverA: Reacted to the event.");
            }
        }
    }

    class ConcreteObserverB : IObserver
    {
        public void Update(ISubject subject)
        {
            if ((subject as Subject).State == 0 || (subject as Subject).State >= 2)
            {
                Console.WriteLine("ConcreteObserverB: Reacted to the event.");
            }
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            // شفرة العميل.
            var subject = new Subject();
            var observerA = new ConcreteObserverA();
            subject.Attach(observerA);

            var observerB = new ConcreteObserverB();
            subject.Attach(observerB);

            subject.SomeBusinessLogic();
            subject.SomeBusinessLogic();

            subject.Detach(observerB);

            subject.SomeBusinessLogic();
        }
    }
}

Subject: Attached an observer.
Subject: Attached an observer.

Subject: I'm doing something important.
Subject: My state has just changed to: 2
Subject: Notifying observers...
ConcreteObserverA: Reacted to the event.
ConcreteObserverB: Reacted to the event.

Subject: I'm doing something important.
Subject: My state has just changed to: 1
Subject: Notifying observers...
ConcreteObserverA: Reacted to the event.
Subject: Detached an observer.

Subject: I'm doing something important.
Subject: My state has just changed to: 5
Subject: Notifying observers...
```

### cpp

```cpp
/**
 * نمط تصميم المراقب
 *
 * الهدف: يتيح لك تحديد آلية اشتراك لإخطار كائنات متعددة
 * بأي أحداث تحدث للكائن الذي يراقبونه.
 *
 * لاحظ أن هناك الكثير من المصطلحات ذات المعنى المتشابه المرتبطة
 * بهذا النمط. تذكر فقط أن الموضوع يُسمى أيضاً الناشر،
 * والمراقب كثيراً ما يُسمى المشترك والعكس صحيح.
 * كما أن الأفعال "يراقب" أو "يستمع" أو "يتتبع" تعني عادةً الشيء ذاته.
 */

#include <iostream>
#include <list>
#include <string>

class IObserver {
 public:
  virtual ~IObserver(){};
  virtual void Update(const std::string &message_from_subject) = 0;
};

class ISubject {
 public:
  virtual ~ISubject(){};
  virtual void Attach(IObserver *observer) = 0;
  virtual void Detach(IObserver *observer) = 0;
  virtual void Notify() = 0;
};

/**
 * يمتلك الموضوع حالة مهمة ويُخطر المراقبين عند تغيُّر الحالة.
 */

class Subject : public ISubject {
 public:
  virtual ~Subject() {
    std::cout << "Goodbye, I was the Subject.\n";
  }

  /**
   * توابع إدارة الاشتراك.
   */
  void Attach(IObserver *observer) override {
    list_observer_.push_back(observer);
  }
  void Detach(IObserver *observer) override {
    list_observer_.remove(observer);
  }
  void Notify() override {
    std::list<IObserver *>::iterator iterator = list_observer_.begin();
    HowManyObserver();
    while (iterator != list_observer_.end()) {
      (*iterator)->Update(message_);
      ++iterator;
    }
  }

  void CreateMessage(std::string message = "Empty") {
    this->message_ = message;
    Notify();
  }
  void HowManyObserver() {
    std::cout << "There are " << list_observer_.size() << " observers in the list.\n";
  }

  /**
   * عادةً ما يمثل منطق الاشتراك جزءاً بسيطاً مما يمكن للموضوع
   * فعله فعلياً. يحتوي الموضوع عادةً على منطق أعمال مهم،
   * يُشغِّل تابع إخطار كلما كان شيء مهم على وشك الحدوث (أو بعده).
   */
  void SomeBusinessLogic() {
    this->message_ = "change message message";
    Notify();
    std::cout << "I'm about to do some thing important\n";
  }

 private:
  std::list<IObserver *> list_observer_;
  std::string message_;
};

class Observer : public IObserver {
 public:
  Observer(Subject &subject) : subject_(subject) {
    this->subject_.Attach(this);
    std::cout << "Hi, I'm the Observer \"" << ++Observer::static_number_ << "\".\n";
    this->number_ = Observer::static_number_;
  }
  virtual ~Observer() {
    std::cout << "Goodbye, I was the Observer \"" << this->number_ << "\".\n";
  }

  void Update(const std::string &message_from_subject) override {
    message_from_subject_ = message_from_subject;
    PrintInfo();
  }
  void RemoveMeFromTheList() {
    subject_.Detach(this);
    std::cout << "Observer \"" << number_ << "\" removed from the list.\n";
  }
  void PrintInfo() {
    std::cout << "Observer \"" << this->number_ << "\": a new message is available --> " << this->message_from_subject_ << "\n";
  }

 private:
  std::string message_from_subject_;
  Subject &subject_;
  static int static_number_;
  int number_;
};

int Observer::static_number_ = 0;

void ClientCode() {
  Subject *subject = new Subject;
  Observer *observer1 = new Observer(*subject);
  Observer *observer2 = new Observer(*subject);
  Observer *observer3 = new Observer(*subject);
  Observer *observer4;
  Observer *observer5;

  subject->CreateMessage("Hello World! :D");
  observer3->RemoveMeFromTheList();

  subject->CreateMessage("The weather is hot today! :p");
  observer4 = new Observer(*subject);

  observer2->RemoveMeFromTheList();
  observer5 = new Observer(*subject);

  subject->CreateMessage("My new car is great! ;)");
  observer5->RemoveMeFromTheList();

  observer4->RemoveMeFromTheList();
  observer1->RemoveMeFromTheList();

  delete observer5;
  delete observer4;
  delete observer3;
  delete observer2;
  delete observer1;
  delete subject;
}

int main() {
  ClientCode();
  return 0;
}

Hi, I'm the Observer "1".
Hi, I'm the Observer "2".
Hi, I'm the Observer "3".
There are 3 observers in the list.
Observer "1": a new message is available --> Hello World! :D
Observer "2": a new message is available --> Hello World! :D
Observer "3": a new message is available --> Hello World! :D
Observer "3" removed from the list.
There are 2 observers in the list.
Observer "1": a new message is available --> The weather is hot today! :p
Observer "2": a new message is available --> The weather is hot today! :p
Hi, I'm the Observer "4".
Observer "2" removed from the list.
Hi, I'm the Observer "5".
There are 3 observers in the list.
Observer "1": a new message is available --> My new car is great! ;)
Observer "4": a new message is available --> My new car is great! ;)
Observer "5": a new message is available --> My new car is great! ;)
Observer "5" removed from the list.
Observer "4" removed from the list.
Observer "1" removed from the list.
Goodbye, I was the Observer "5".
Goodbye, I was the Observer "4".
Goodbye, I was the Observer "3".
Goodbye, I was the Observer "2".
Goodbye, I was the Observer "1".
Goodbye, I was the Subject.
```

### go

```go
package main

type Subject interface {
	register(observer Observer)
	deregister(observer Observer)
	notifyAll()
}

package main

import "fmt"

type Item struct {
	observerList []Observer
	name         string
	inStock      bool
}

func newItem(name string) *Item {
	return &Item{
		name: name,
	}
}
func (i *Item) updateAvailability() {
	fmt.Printf("Item %s is now in stock\n", i.name)
	i.inStock = true
	i.notifyAll()
}
func (i *Item) register(o Observer) {
	i.observerList = append(i.observerList, o)
}

func (i *Item) deregister(o Observer) {
	i.observerList = removeFromslice(i.observerList, o)
}

func (i *Item) notifyAll() {
	for _, observer := range i.observerList {
		observer.update(i.name)
	}
}

func removeFromslice(observerList []Observer, observerToRemove Observer) []Observer {
	observerListLength := len(observerList)
	for i, observer := range observerList {
		if observerToRemove.getID() == observer.getID() {
			observerList[observerListLength-1], observerList[i] = observerList[i], observerList[observerListLength-1]
			return observerList[:observerListLength-1]
		}
	}
	return observerList
}

package main

type Observer interface {
	update(string)
	getID() string
}

package main

import "fmt"

type Customer struct {
	id string
}

func (c *Customer) update(itemName string) {
	fmt.Printf("Sending email to customer %s for item %s\n", c.id, itemName)
}

func (c *Customer) getID() string {
	return c.id
}

package main

func main() {

	shirtItem := newItem("Nike Shirt")

	observerFirst := &Customer{id: "abc@gmail.com"}
	observerSecond := &Customer{id: "xyz@gmail.com"}

	shirtItem.register(observerFirst)
	shirtItem.register(observerSecond)

	shirtItem.updateAvailability()
}

Item Nike Shirt is now in stock
Sending email to customer abc@gmail.com for item Nike Shirt
Sending email to customer xyz@gmail.com for item Nike Shirt
```

### php

```php
<?php

namespace RefactoringGuru\Observer\Conceptual;

/**
 * يحتوي PHP على بعض الواجهات المدمجة المتعلقة بنمط المراقب.
 *
 * هذا ما تبدو عليه واجهة الموضوع:
 *
 * @link http://php.net/manual/en/class.splsubject.php
 *
 *     interface SplSubject
 *     {
 *         // ربط مراقب بالموضوع.
 *         public function attach(SplObserver $observer);
 *
 *         // فصل مراقب من الموضوع.
 *         public function detach(SplObserver $observer);
 *
 *         // إخطار جميع المراقبين بحدث.
 *         public function notify();
 *     }
 *
 * هناك أيضاً واجهة مدمجة للمراقبين:
 *
 * @link http://php.net/manual/en/class.splobserver.php
 *
 *     interface SplObserver
 *     {
 *         public function update(SplSubject $subject);
 *     }
 */

/**
 * يمتلك الموضوع حالة مهمة ويُخطر المراقبين عند تغيُّر الحالة.
 */
class Subject implements \SplSubject
{
    /**
     * @var int من أجل التبسيط، تُخزَّن حالة الموضوع الضرورية لجميع المشتركين في هذا المتغير.
     */
    public $state;

    /**
     * @var \SplObjectStorage قائمة المشتركين. في الواقع العملي، يمكن تخزين قائمة المشتركين
     * بصورة أشمل (مصنفةً حسب نوع الحدث، وما إلى ذلك).
     */
    private $observers;

    public function __construct()
    {
        $this->observers = new \SplObjectStorage();
    }

    /**
     * توابع إدارة الاشتراك.
     */
    public function attach(\SplObserver $observer): void
    {
        echo "Subject: Attached an observer.\n";
        $this->observers->attach($observer);
    }

    public function detach(\SplObserver $observer): void
    {
        $this->observers->detach($observer);
        echo "Subject: Detached an observer.\n";
    }

    /**
     * تشغيل تحديث في كل مشترك.
     */
    public function notify(): void
    {
        echo "Subject: Notifying observers...\n";
        foreach ($this->observers as $observer) {
            $observer->update($this);
        }
    }

    /**
     * عادةً ما يمثل منطق الاشتراك جزءاً بسيطاً مما يمكن للموضوع
     * فعله فعلياً. يحتوي الموضوع عادةً على منطق أعمال مهم،
     * يُشغِّل تابع إخطار كلما كان شيء مهم على وشك الحدوث (أو بعده).
     */
    public function someBusinessLogic(): void
    {
        echo "\nSubject: I'm doing something important.\n";
        $this->state = rand(0, 10);

        echo "Subject: My state has just changed to: {$this->state}\n";
        $this->notify();
    }
}

/**
 * يتفاعل المراقبون الملموسون مع التحديثات الصادرة عن الموضوع الذي ارتبطوا به.
 */
class ConcreteObserverA implements \SplObserver
{
    public function update(\SplSubject $subject): void
    {
        if ($subject->state < 3) {
            echo "ConcreteObserverA: Reacted to the event.\n";
        }
    }
}

class ConcreteObserverB implements \SplObserver
{
    public function update(\SplSubject $subject): void
    {
        if ($subject->state == 0 || $subject->state >= 2) {
            echo "ConcreteObserverB: Reacted to the event.\n";
        }
    }
}

/**
 * شفرة العميل.
 */

$subject = new Subject();

$o1 = new ConcreteObserverA();
$subject->attach($o1);

$o2 = new ConcreteObserverB();
$subject->attach($o2);

$subject->someBusinessLogic();
$subject->someBusinessLogic();

$subject->detach($o2);

$subject->someBusinessLogic();

Subject: Attached an observer.
Subject: Attached an observer.

Subject: I'm doing something important.
Subject: My state has just changed to: 2
Subject: Notifying observers...
ConcreteObserverA: Reacted to the event.
ConcreteObserverB: Reacted to the event.

Subject: I'm doing something important.
Subject: My state has just changed to: 4
Subject: Notifying observers...
ConcreteObserverB: Reacted to the event.
Subject: Detached an observer.

Subject: I'm doing something important.
Subject: My state has just changed to: 1
Subject: Notifying observers...
ConcreteObserverA: Reacted to the event.

<?php

namespace RefactoringGuru\Observer\RealWorld;

/**
 * The UserRepository represents a Subject. Various objects are interested in
 * tracking its internal state, whether it's adding a new user or removing one.
 */
class UserRepository implements \SplSubject
{
    /**
     * @var array The list of users.
     */
    private $users = [];

    // هنا توجد البنية التحتية الفعلية لإدارة المراقب. لاحظ أن هذا
    // ليس كل ما تتحمل مسؤوليته فئتنا. منطق الأعمال الأساسي
    // مدرج أدناه هذه التوابع.

    /**
     * @var array
     */
    private $observers = [];

    public function __construct()
    {
        // مجموعة أحداث خاصة للمراقبين الذين يريدون الاستماع إلى جميع الأحداث.
        $this->observers["*"] = [];
    }

    private function initEventGroup(string $event = "*"): void
    {
        if (!isset($this->observers[$event])) {
            $this->observers[$event] = [];
        }
    }

    private function getEventObservers(string $event = "*"): array
    {
        $this->initEventGroup($event);
        $group = $this->observers[$event];
        $all = $this->observers["*"];

        return array_merge($group, $all);
    }

    public function attach(\SplObserver $observer, string $event = "*"): void
    {
        $this->initEventGroup($event);

        $this->observers[$event][] = $observer;
    }

    public function detach(\SplObserver $observer, string $event = "*"): void
    {
        foreach ($this->getEventObservers($event) as $key => $s) {
            if ($s === $observer) {
                unset($this->observers[$event][$key]);
            }
        }
    }

    public function notify(string $event = "*", $data = null): void
    {
        echo "UserRepository: Broadcasting the '$event' event.\n";
        foreach ($this->getEventObservers($event) as $observer) {
            $observer->update($this, $event, $data);
        }
    }

    // هنا التوابع التي تمثل منطق أعمال الفئة.

    public function initialize($filename): void
    {
        echo "UserRepository: Loading user records from a file.\n";
        // ...
        $this->notify("users:init", $filename);
    }

    public function createUser(array $data): User
    {
        echo "UserRepository: Creating a user.\n";

        $user = new User();
        $user->update($data);

        $id = bin2hex(openssl_random_pseudo_bytes(16));
        $user->update(["id" => $id]);
        $this->users[$id] = $user;

        $this->notify("users:created", $user);

        return $user;
    }

    public function updateUser(User $user, array $data): User
    {
        echo "UserRepository: Updating a user.\n";

        $id = $user->attributes["id"];
        if (!isset($this->users[$id])) {
            return null;
        }

        $user = $this->users[$id];
        $user->update($data);

        $this->notify("users:updated", $user);

        return $user;
    }

    public function deleteUser(User $user): void
    {
        echo "UserRepository: Deleting a user.\n";

        $id = $user->attributes["id"];
        if (!isset($this->users[$id])) {
            return;
        }

        unset($this->users[$id]);

        $this->notify("users:deleted", $user);
    }
}

/**
 * سنبقي فئة User بسيطة لأنها ليست محور مثالنا.
 */
class User
{
    public $attributes = [];

    public function update($data): void
    {
        $this->attributes = array_merge($this->attributes, $data);
    }
}

/**
 * يُسجِّل هذا المكوّن الملموس أي أحداث اشترك فيها.
 */
class Logger implements \SplObserver
{
    private $filename;

    public function __construct($filename)
    {
        $this->filename = $filename;
        if (file_exists($this->filename)) {
            unlink($this->filename);
        }
    }

    public function update(\SplSubject $repository, string $event = null, $data = null): void
    {
        $entry = date("Y-m-d H:i:s") . ": '$event' with data '" . json_encode($data) . "'\n";
        file_put_contents($this->filename, $entry, FILE_APPEND);

        echo "Logger: I've written '$event' entry to the log.\n";
    }
}

/**
 * يرسل هذا المكوّن الملموس تعليمات أولية للمستخدمين الجدد. العميل
 * مسؤول عن ربط هذا المكوّن بحدث إنشاء المستخدم المناسب.
 */
class OnboardingNotification implements \SplObserver
{
    private $adminEmail;

    public function __construct($adminEmail)
    {
        $this->adminEmail = $adminEmail;
    }

    public function update(\SplSubject $repository, string $event = null, $data = null): void
    {
        // mail($this->adminEmail,
        //     "Onboarding required",
        //     "We have a new user. Here's his info: " .json_encode($data));

        echo "OnboardingNotification: The notification has been emailed!\n";
    }
}

/**
 * شفرة العميل.
 */

$repository = new UserRepository();
$repository->attach(new Logger(__DIR__ . "/log.txt"), "*");
$repository->attach(new OnboardingNotification("1@example.com"), "users:created");

$repository->initialize(__DIR__ . "/users.csv");

// ...

$user = $repository->createUser([
    "name" => "John Smith",
    "email" => "john99@example.com",
]);

// ...

$repository->deleteUser($user);

UserRepository: Loading user records from a file.
UserRepository: Broadcasting the 'users:init' event.
Logger: I've written 'users:init' entry to the log.
UserRepository: Creating a user.
UserRepository: Broadcasting the 'users:created' event.
OnboardingNotification: The notification has been emailed!
Logger: I've written 'users:created' entry to the log.
UserRepository: Deleting a user.
UserRepository: Broadcasting the 'users:deleted' event.
Logger: I've written 'users:deleted' entry to the log.
```

### python

```python
from __future__ import annotations
from abc import ABC, abstractmethod
from random import randrange
from typing import List


class Subject(ABC):
    """
    تُعلن واجهة الموضوع عن مجموعة من التوابع لإدارة المشتركين.
    """

    @abstractmethod
    def attach(self, observer: Observer) -> None:
        """
        ربط مراقب بالموضوع.
        """
        pass

    @abstractmethod
    def detach(self, observer: Observer) -> None:
        """
        فصل مراقب من الموضوع.
        """
        pass

    @abstractmethod
    def notify(self) -> None:
        """
        إخطار جميع المراقبين بحدث.
        """
        pass


class ConcreteSubject(Subject):
    """
    يمتلك الموضوع حالة مهمة ويُخطر المراقبين عند تغيُّر الحالة.
    """

    _state: int = None
    """
    من أجل التبسيط، تُخزَّن حالة الموضوع الضرورية لجميع المشتركين في هذا المتغير.
    """

    _observers: List[Observer] = []
    """
    قائمة المشتركين. في الواقع العملي، يمكن تخزين قائمة المشتركين
    بصورة أشمل (مصنفةً حسب نوع الحدث، وما إلى ذلك).
    """

    def attach(self, observer: Observer) -> None:
        print("Subject: Attached an observer.")
        self._observers.append(observer)

    def detach(self, observer: Observer) -> None:
        self._observers.remove(observer)

    """
    توابع إدارة الاشتراك.
    """

    def notify(self) -> None:
        """
        تشغيل تحديث في كل مشترك.
        """

        print("Subject: Notifying observers...")
        for observer in self._observers:
            observer.update(self)

    def some_business_logic(self) -> None:
        """
        عادةً ما يمثل منطق الاشتراك جزءاً بسيطاً مما يمكن للموضوع فعله فعلياً.
        يحتوي الموضوع عادةً على منطق أعمال مهم، يُشغِّل تابع إخطار كلما كان
        شيء مهم على وشك الحدوث (أو بعده).
        """

        print("\nSubject: I'm doing something important.")
        self._state = randrange(0, 10)

        print(f"Subject: My state has just changed to: {self._state}")
        self.notify()


class Observer(ABC):
    """
    تُعلن واجهة المراقب عن تابع التحديث الذي تستخدمه الموضوعات.
    """

    @abstractmethod
    def update(self, subject: Subject) -> None:
        """
        استقبال تحديث من الموضوع.
        """
        pass


"""
يتفاعل المراقبون الملموسون مع التحديثات الصادرة عن الموضوع الذي ارتبطوا به.
"""


class ConcreteObserverA(Observer):
    def update(self, subject: Subject) -> None:
        if subject._state < 3:
            print("ConcreteObserverA: Reacted to the event")


class ConcreteObserverB(Observer):
    def update(self, subject: Subject) -> None:
        if subject._state == 0 or subject._state >= 2:
            print("ConcreteObserverB: Reacted to the event")


if __name__ == "__main__":
    # شفرة العميل.

    subject = ConcreteSubject()

    observer_a = ConcreteObserverA()
    subject.attach(observer_a)

    observer_b = ConcreteObserverB()
    subject.attach(observer_b)

    subject.some_business_logic()
    subject.some_business_logic()

    subject.detach(observer_a)

    subject.some_business_logic()

Subject: Attached an observer.
Subject: Attached an observer.

Subject: I'm doing something important.
Subject: My state has just changed to: 0
Subject: Notifying observers...
ConcreteObserverA: Reacted to the event
ConcreteObserverB: Reacted to the event

Subject: I'm doing something important.
Subject: My state has just changed to: 5
Subject: Notifying observers...
ConcreteObserverB: Reacted to the event

Subject: I'm doing something important.
Subject: My state has just changed to: 0
Subject: Notifying observers...
ConcreteObserverB: Reacted to the event
```

### ruby

```ruby
# تُعلن واجهة الموضوع عن مجموعة من التوابع لإدارة المشتركين.
class Subject
  # ربط مراقب بالموضوع.
  def attach(observer)
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end

  # فصل مراقب من الموضوع.
  def detach(observer)
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end

  # إخطار جميع المراقبين بحدث.
  def notify
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end

# يمتلك الموضوع حالة مهمة ويُخطر المراقبين عند تغيُّر الحالة.
class ConcreteSubject < Subject
  # من أجل التبسيط، تُخزَّن حالة الموضوع الضرورية لجميع المشتركين في هذا المتغير.
  attr_accessor :state

  # @!attribute observers
  # @return [Array<Observer>] attr_accessor :observers private :observers

  def initialize
    @observers = []
  end

  # قائمة المشتركين. في الواقع العملي، يمكن تخزين قائمة المشتركين
  # بصورة أشمل (مصنفةً حسب نوع الحدث، وما إلى ذلك).

  # @param [Observer] observer
  def attach(observer)
    puts 'Subject: Attached an observer.'
    @observers << observer
  end

  # @param [Observer] observer
  def detach(observer)
    @observers.delete(observer)
  end

  # توابع إدارة الاشتراك.

  # تشغيل تحديث في كل مشترك.
  def notify
    puts 'Subject: Notifying observers...'
    @observers.each { |observer| observer.update(self) }
  end

  # عادةً ما يمثل منطق الاشتراك جزءاً بسيطاً مما يمكن للموضوع فعله فعلياً.
  # يحتوي الموضوع عادةً على منطق أعمال مهم، يُشغِّل تابع إخطار كلما كان
  # شيء مهم على وشك الحدوث (أو بعده).
  def some_business_logic
    puts "\nSubject: I'm doing something important."
    @state = rand(0..10)

    puts "Subject: My state has just changed to: #{@state}"
    notify
  end
end

# تُعلن واجهة المراقب عن تابع التحديث الذي تستخدمه الموضوعات.
class Observer
  # استقبال تحديث من الموضوع.
  def update(_subject)
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end

# يتفاعل المراقبون الملموسون مع التحديثات الصادرة عن الموضوع الذي ارتبطوا به.

class ConcreteObserverA < Observer
  # @param [Subject] subject
  def update(subject)
    puts 'ConcreteObserverA: Reacted to the event' if subject.state < 3
  end
end

class ConcreteObserverB < Observer
  # @param [Subject] subject
  def update(subject)
    return unless subject.state.zero? || subject.state >= 2

    puts 'ConcreteObserverB: Reacted to the event'
  end
end

# شفرة العميل.

subject = ConcreteSubject.new

observer_a = ConcreteObserverA.new
subject.attach(observer_a)

observer_b = ConcreteObserverB.new
subject.attach(observer_b)

subject.some_business_logic
subject.some_business_logic

subject.detach(observer_a)

subject.some_business_logic

Subject: Attached an observer.
Subject: Attached an observer.

Subject: I'm doing something important.
Subject: My state has just changed to: 1
Subject: Notifying observers...
ConcreteObserverA: Reacted to the event

Subject: I'm doing something important.
Subject: My state has just changed to: 10
Subject: Notifying observers...
ConcreteObserverB: Reacted to the event

Subject: I'm doing something important.
Subject: My state has just changed to: 2
Subject: Notifying observers...
ConcreteObserverB: Reacted to the event
```

### rust

```rust
use crate::observer::{Event, Publisher};

/// يمتلك المحرر منطقه الخاص ويستخدم الناشر
/// للتعامل مع المشتركين والأحداث.
#[derive(Default)]
pub struct Editor {
    publisher: Publisher,
    file_path: String,
}

impl Editor {
    pub fn events(&mut self) -> &mut Publisher {
        &mut self.publisher
    }

    pub fn load(&mut self, path: String) {
        self.file_path = path.clone();
        self.publisher.notify(Event::Load, path);
    }

    pub fn save(&self) {
        self.publisher.notify(Event::Save, self.file_path.clone());
    }
}

use std::collections::HashMap;

/// نوع الحدث.
#[derive(PartialEq, Eq, Hash, Clone)]
pub enum Event {
    Load,
    Save,
}

/// نوع المشترك (المستمع) هو دالة قابلة للاستدعاء.
pub type Subscriber = fn(file_path: String);

/// يرسل الناشر الأحداث إلى المشتركين (المستمعين).
#[derive(Default)]
pub struct Publisher {
    events: HashMap<Event, Vec<Subscriber>>,
}

impl Publisher {
    pub fn subscribe(&mut self, event_type: Event, listener: Subscriber) {
        self.events.entry(event_type.clone()).or_default();
        self.events.get_mut(&event_type).unwrap().push(listener);
    }

    pub fn unsubscribe(&mut self, event_type: Event, listener: Subscriber) {
        self.events
            .get_mut(&event_type)
            .unwrap()
            .retain(|&x| x != listener);
    }

    pub fn notify(&self, event_type: Event, file_path: String) {
        let listeners = self.events.get(&event_type).unwrap();
        for listener in listeners {
            listener(file_path.clone());
        }
    }
}

use editor::Editor;
use observer::Event;

mod editor;
mod observer;

fn main() {
    let mut editor = Editor::default();

    editor.events().subscribe(Event::Load, |file_path| {
        let log = "/path/to/log/file.txt".to_string();
        println!("Save log to {}: Load file {}", log, file_path);
    });

    editor.events().subscribe(Event::Save, save_listener);

    editor.load("test1.txt".into());
    editor.load("test2.txt".into());
    editor.save();

    editor.events().unsubscribe(Event::Save, save_listener);
    editor.save();
}

fn save_listener(file_path: String) {
    let email = "admin@example.com".to_string();
    println!("Email to {}: Save file {}", email, file_path);
}

Save log to /path/to/log/file.txt: Load file test1.txt
Save log to /path/to/log/file.txt: Load file test2.txt
Email to admin@example.com: Save file test2.txt
```

### swift

```swift
import XCTest

/// يمتلك الموضوع حالة مهمة ويُخطر المراقبين عند تغيُّر الحالة.
class Subject {

    /// من أجل التبسيط، تُخزَّن حالة الموضوع الضرورية لجميع المشتركين في هذا المتغير.
    var state: Int = { return Int(arc4random_uniform(10)) }()

    /// @var array قائمة المشتركين. في الواقع العملي، يمكن تخزين قائمة المشتركين
    /// بصورة أشمل (مصنفةً حسب نوع الحدث، وما إلى ذلك).
    private lazy var observers = [Observer]()

    /// توابع إدارة الاشتراك.
    func attach(_ observer: Observer) {
        print("Subject: Attached an observer.\n")
        observers.append(observer)
    }

    func detach(_ observer: Observer) {
        if let idx = observers.firstIndex(where: { $0 === observer }) {
            observers.remove(at: idx)
            print("Subject: Detached an observer.\n")
        }
    }

    /// تشغيل تحديث في كل مشترك.
    func notify() {
        print("Subject: Notifying observers...\n")
        observers.forEach({ $0.update(subject: self)})
    }

    /// عادةً ما يمثل منطق الاشتراك جزءاً بسيطاً مما يمكن للموضوع فعله فعلياً.
    /// يحتوي الموضوع عادةً على منطق أعمال مهم، يُشغِّل تابع إخطار كلما كان
    /// شيء مهم على وشك الحدوث (أو بعده).
    func someBusinessLogic() {
        print("\nSubject: I'm doing something important.\n")
        state = Int(arc4random_uniform(10))
        print("Subject: My state has just changed to: \(state)\n")
        notify()
    }
}

/// يُعلن بروتوكول المراقب عن تابع التحديث الذي تستخدمه الموضوعات.
protocol Observer: AnyObject {

    func update(subject: Subject)
}

/// يتفاعل المراقبون الملموسون مع التحديثات الصادرة عن الموضوع الذي ارتبطوا به.
class ConcreteObserverA: Observer {

    func update(subject: Subject) {

        if subject.state < 3 {
            print("ConcreteObserverA: Reacted to the event.\n")
        }
    }
}

class ConcreteObserverB: Observer {

    func update(subject: Subject) {

        if subject.state >= 3 {
            print("ConcreteObserverB: Reacted to the event.\n")
        }
    }
}

/// دعنا نرى كيف يعمل كل شيء معاً.
class ObserverConceptual: XCTestCase {

    func testObserverConceptual() {

        let subject = Subject()

        let observer1 = ConcreteObserverA()
        let observer2 = ConcreteObserverB()

        subject.attach(observer1)
        subject.attach(observer2)

        subject.someBusinessLogic()
        subject.someBusinessLogic()
        subject.detach(observer2)
        subject.someBusinessLogic()
    }
}

Subject: Attached an observer.

Subject: Attached an observer.


Subject: I'm doing something important.

Subject: My state has just changed to: 4

Subject: Notifying observers...

ConcreteObserverB: Reacted to the event.


Subject: I'm doing something important.

Subject: My state has just changed to: 2

Subject: Notifying observers...

ConcreteObserverA: Reacted to the event.

Subject: Detached an observer.


Subject: I'm doing something important.

Subject: My state has just changed to: 8

Subject: Notifying observers...

import XCTest

class ObserverRealWorld: XCTestCase {

    func test() {

        let cartManager = CartManager()

        let navigationBar = UINavigationBar()
        let cartVC = CartViewController()

        cartManager.add(subscriber: navigationBar)
        cartManager.add(subscriber: cartVC)

        let apple = Food(id: 111, name: "Apple", price: 10, calories: 20)
        cartManager.add(product: apple)

        let tShirt = Clothes(id: 222, name: "T-shirt", price: 200, size: "L")
        cartManager.add(product: tShirt)

        cartManager.remove(product: apple)
    }
}

protocol CartSubscriber: CustomStringConvertible {

    func accept(changed cart: [Product])
}

protocol Product {

    var id: Int { get }
    var name: String { get }
    var price: Double { get }

    func isEqual(to product: Product) -> Bool
}

extension Product {

    func isEqual(to product: Product) -> Bool {
        return id == product.id
    }
}

struct Food: Product {

    var id: Int
    var name: String
    var price: Double

    /// خصائص خاصة بالأطعمة
    var calories: Int
}

struct Clothes: Product {

    var id: Int
    var name: String
    var price: Double

    /// خصائص خاصة بالملابس
    var size: String
}

class CartManager {

    private lazy var cart = [Product]()
    private lazy var subscribers = [CartSubscriber]()

    func add(subscriber: CartSubscriber) {
        print("CartManager: I'am adding a new subscriber: \(subscriber.description)")
        subscribers.append(subscriber)
    }

    func add(product: Product) {
        print("\nCartManager: I'am adding a new product: \(product.name)")
        cart.append(product)
        notifySubscribers()
    }

    func remove(subscriber filter: (CartSubscriber) -> (Bool)) {
        guard let index = subscribers.firstIndex(where: filter) else { return }
        subscribers.remove(at: index)
    }

    func remove(product: Product) {
        guard let index = cart.firstIndex(where: { $0.isEqual(to: product) }) else { return }
        print("\nCartManager: Product '\(product.name)' is removed from a cart")
        cart.remove(at: index)
        notifySubscribers()
    }

    private func notifySubscribers() {
        subscribers.forEach({ $0.accept(changed: cart) })
    }
}

extension UINavigationBar: CartSubscriber {

    func accept(changed cart: [Product]) {
        print("UINavigationBar: Updating an appearance of navigation items")
    }

    open override var description: String { return "UINavigationBar" }
}

class CartViewController: UIViewController, CartSubscriber {

    func accept(changed cart: [Product]) {
        print("CartViewController: Updating an appearance of a list view with products")
    }

    open override var description: String { return "CartViewController" }
}

CartManager: I'am adding a new subscriber: UINavigationBar
CartManager: I'am adding a new subscriber: CartViewController

CartManager: I'am adding a new product: Apple
UINavigationBar: Updating an appearance of navigation items
CartViewController: Updating an appearance of a list view with products

CartManager: I'am adding a new product: T-shirt
UINavigationBar: Updating an appearance of navigation items
CartViewController: Updating an appearance of a list view with products

CartManager: Product 'Apple' is removed from a cart
UINavigationBar: Updating an appearance of navigation items
CartViewController: Updating an appearance of a list view with products
```

### typescript

```typescript
/**
 * تُعلن واجهة الموضوع عن مجموعة من التوابع لإدارة المشتركين.
 */
interface Subject {
    // ربط مراقب بالموضوع.
    attach(observer: Observer): void;

    // فصل مراقب من الموضوع.
    detach(observer: Observer): void;

    // إخطار جميع المراقبين بحدث.
    notify(): void;
}

/**
 * يمتلك الموضوع حالة مهمة ويُخطر المراقبين عند تغيُّر الحالة.
 */
class ConcreteSubject implements Subject {
    /**
     * @type {number} من أجل التبسيط، تُخزَّن حالة الموضوع الضرورية
     * لجميع المشتركين في هذا المتغير.
     */
    public state: number;

    /**
     * @type {Observer[]} قائمة المشتركين. في الواقع العملي، يمكن تخزين
     * قائمة المشتركين بصورة أشمل (مصنفةً حسب نوع الحدث، وما إلى ذلك).
     */
    private observers: Observer[] = [];

    /**
     * توابع إدارة الاشتراك.
     */
    public attach(observer: Observer): void {
        const isExist = this.observers.includes(observer);
        if (isExist) {
            return console.log('Subject: Observer has been attached already.');
        }

        console.log('Subject: Attached an observer.');
        this.observers.push(observer);
    }

    public detach(observer: Observer): void {
        const observerIndex = this.observers.indexOf(observer);
        if (observerIndex === -1) {
            return console.log('Subject: Nonexistent observer.');
        }

        this.observers.splice(observerIndex, 1);
        console.log('Subject: Detached an observer.');
    }

    /**
     * تشغيل تحديث في كل مشترك.
     */
    public notify(): void {
        console.log('Subject: Notifying observers...');
        for (const observer of this.observers) {
            observer.update(this);
        }
    }

    /**
     * عادةً ما يمثل منطق الاشتراك جزءاً بسيطاً مما يمكن للموضوع فعله فعلياً.
     * يحتوي الموضوع عادةً على منطق أعمال مهم، يُشغِّل تابع إخطار كلما كان
     * شيء مهم على وشك الحدوث (أو بعده).
     */
    public someBusinessLogic(): void {
        console.log('\nSubject: I\'m doing something important.');
        this.state = Math.floor(Math.random() * (10 + 1));

        console.log(`Subject: My state has just changed to: ${this.state}`);
        this.notify();
    }
}

/**
 * تُعلن واجهة المراقب عن تابع التحديث الذي تستخدمه الموضوعات.
 */
interface Observer {
    // استقبال تحديث من الموضوع.
    update(subject: Subject): void;
}

/**
 * يتفاعل المراقبون الملموسون مع التحديثات الصادرة عن الموضوع الذي ارتبطوا به.
 */
class ConcreteObserverA implements Observer {
    public update(subject: Subject): void {
        if (subject instanceof ConcreteSubject && subject.state < 3) {
            console.log('ConcreteObserverA: Reacted to the event.');
        }
    }
}

class ConcreteObserverB implements Observer {
    public update(subject: Subject): void {
        if (subject instanceof ConcreteSubject && (subject.state === 0 || subject.state >= 2)) {
            console.log('ConcreteObserverB: Reacted to the event.');
        }
    }
}

/**
 * شفرة العميل.
 */

const subject = new ConcreteSubject();

const observer1 = new ConcreteObserverA();
subject.attach(observer1);

const observer2 = new ConcreteObserverB();
subject.attach(observer2);

subject.someBusinessLogic();
subject.someBusinessLogic();

subject.detach(observer2);

subject.someBusinessLogic();

Subject: Attached an observer.
Subject: Attached an observer.

Subject: I'm doing something important.
Subject: My state has just changed to: 6
Subject: Notifying observers...
ConcreteObserverB: Reacted to the event.

Subject: I'm doing something important.
Subject: My state has just changed to: 1
Subject: Notifying observers...
ConcreteObserverA: Reacted to the event.
Subject: Detached an observer.

Subject: I'm doing something important.
Subject: My state has just changed to: 5
Subject: Notifying observers...
```

