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

> الوسيط هو نمط تصميم سلوكي يُتيح لك تقليل الاعتماديات الفوضوية بين الكائنات. يقيّد النمط الاتصالات المباشرة بين الكائنات ويُجبرها على التعاون فقط عبر كائن وسيط.

## Intent

**الوسيط** هو نمط تصميم سلوكي يُتيح لك تقليل الاعتماديات الفوضوية بين الكائنات. يقيّد النمط الاتصالات المباشرة بين الكائنات ويُجبرها على التعاون فقط عبر كائن وسيط.

## Problem

لنفترض أن لديك مربع حوار لإنشاء ملفات تعريف العملاء وتحريرها. يتألف من عناصر تحكم متنوعة في النموذج كحقول النصوص ومربعات الاختيار والأزرار وغيرها.

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

قد تتفاعل بعض عناصر النموذج مع عناصر أخرى. على سبيل المثال، قد يؤدي تحديد مربع الاختيار "لدي كلب" إلى إظهار حقل نص مخفي لإدخال اسم الكلب. مثال آخر هو زر الإرسال الذي يجب أن يتحقق من قيم جميع الحقول قبل حفظ البيانات.

قد يكون للعناصر علاقات كثيرة مع عناصر أخرى. وبالتالي، قد تؤثر التغييرات في بعض العناصر على الأخرى.

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

## Solution

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

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

يجب أن تتواصل عناصر واجهة المستخدم بشكل غير مباشر، عبر كائن الوسيط.

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

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

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

## Structure

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

## Pseudocode

في هذا المثال، يساعدك نمط **الوسيط** على إزالة الاعتماديات المتبادلة بين فئات واجهة المستخدم المختلفة: الأزرار ومربعات الاختيار وتسميات النصوص.

هيكل فئات مربع حوار واجهة المستخدم.

An element, triggered by a user, doesn’t communicate with other elements directly, even if it looks like it’s supposed to. Instead, the element only needs to let its mediator know about the event, passing any contextual info along with that notification.

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

// تُعلن واجهة الوسيط عن طريقة تستخدمها المكوّنات
// لإخطار الوسيط بأحداث متنوعة. قد يستجيب الوسيط
// لهذه الأحداث ويمرر التنفيذ إلى مكوّنات أخرى.
interface Mediator is
    method notify(sender: Component, event: string)

// فئة الوسيط الملموس. الشبكة المتشابكة من
// الاتصالات بين المكوّنات الفردية قد تم فكّها
// ونقلها إلى الوسيط.
class AuthenticationDialog implements Mediator is
    private field title: string
    private field loginOrRegisterChkBx: Checkbox
    private field loginUsername, loginPassword: Textbox
    private field registrationUsername, registrationPassword,
                  registrationEmail: Textbox
    private field okBtn, cancelBtn: Button

    constructor AuthenticationDialog() is
        // أنشئ جميع كائنات المكوّنات عن طريق تمرير الوسيط الحالي
        // إلى منشئاتها لإنشاء الروابط.

    // عندما يحدث شيء ما لمكوّن ما، يُخطر الوسيط.
    // عند استلام إشعار، قد يفعل الوسيط شيئاً بنفسه
    // أو يمرر الطلب إلى مكوّن آخر.
    method notify(sender, event) is
        if (sender == loginOrRegisterChkBx and event == "check")
            if (loginOrRegisterChkBx.checked)
                title = "Log in"
                // 1. أظهر مكوّنات نموذج تسجيل الدخول.
                // 2. أخفِ مكوّنات نموذج التسجيل.
            else
                title = "Register"
                // 1. أظهر مكوّنات نموذج التسجيل.
                // 2. أخفِ مكوّنات نموذج تسجيل الدخول.

        if (sender == okBtn && event == "click")
            if (loginOrRegister.checked)
                // حاول إيجاد مستخدم باستخدام بيانات تسجيل الدخول.
                if (!found)
                    // أظهر رسالة خطأ فوق حقل
                    // تسجيل الدخول.
            else
                // 1. أنشئ حساب مستخدم باستخدام البيانات من
                // حقول التسجيل.
                // 2. سجّل دخول ذلك المستخدم.
                // ...

// تتواصل المكوّنات مع الوسيط باستخدام واجهة الوسيط.
// بفضل ذلك، يمكنك استخدام نفس المكوّنات في
// سياقات أخرى عن طريق ربطها بكائنات وسيط مختلفة.
class Component is
    field dialog: Mediator

    constructor Component(dialog) is
        this.dialog = dialog

    method click() is
        dialog.notify(this, "click")

    method keypress() is
        dialog.notify(this, "keypress")

// لا تتحدث المكوّنات الملموسة مع بعضها. لديها قناة
// تواصل واحدة فقط وهي إرسال الإشعارات إلى الوسيط.
class Button extends Component is
    // ...

class Textbox extends Component is
    // ...

class Checkbox extends Component is
    method check() is
        dialog.notify(this, "check")
    // ...

## Applicability

استخدم نمط الوسيط عندما يصعب تغيير بعض الفئات لأنها مرتبطة ارتباطاً وثيقاً بعدد من الفئات الأخرى.

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

 استخدم النمط عندما لا تستطيع إعادة استخدام مكوّن في برنامج آخر لأنه يعتمد بشكل مفرط على مكوّنات أخرى.

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

 استخدم الوسيط عندما تجد نفسك تُنشئ الكثير من الفئات الفرعية للمكوّنات فقط لإعادة استخدام سلوك أساسي في سياقات متنوعة.

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

## How to Implement

1. حدّد مجموعة من الفئات المترابطة بإحكام والتي ستستفيد من مزيد من الاستقلالية (مثلاً، لتسهيل الصيانة أو إعادة الاستخدام).
2. أعلن عن واجهة الوسيط وصف بروتوكول الاتصال المطلوب بين الوسطاء والمكوّنات المختلفة. في معظم الحالات، يكفي طريقة واحدة لاستقبال الإشعارات من المكوّنات.
هذه الواجهة ضرورية عندما تريد إعادة استخدام فئات المكوّنات في سياقات مختلفة. طالما يعمل المكوّن مع وسيطه عبر الواجهة العامة، يمكنك ربط المكوّن بتنفيذ مختلف للوسيط.
3. نفّذ فئة الوسيط الملموس. فكّر في تخزين مراجع لجميع المكوّنات داخل الوسيط. بهذه الطريقة، يمكنك استدعاء أي مكوّن من طرق الوسيط.
4. يمكنك أن تذهب أبعد من ذلك وتجعل الوسيط مسؤولاً عن إنشاء وإتلاف كائنات المكوّنات. بعد ذلك، قد يشبه الوسيط [مصنعاً](/ar/design-patterns/abstract-factory) أو [واجهةً](/ar/design-patterns/facade).
5. يجب أن تخزّن المكوّنات مرجعاً لكائن الوسيط. تُنشأ الاتصال عادةً في منشئ المكوّن، حيث يُمرَّر كائن الوسيط كوسيط.
6. غيّر كود المكوّنات حتى تستدعي طريقة الإشعار للوسيط بدلاً من طرق المكوّنات الأخرى. استخرج الكود الذي يستدعي مكوّنات أخرى في فئة الوسيط. نفّذ هذا الكود كلما تلقى الوسيط إشعارات من ذلك المكوّن.

## Pros

* _مبدأ المسؤولية الواحدة_. يمكنك استخراج الاتصالات بين المكوّنات المختلفة في مكان واحد، مما يجعل الأمر أسهل للفهم والصيانة.
* _مبدأ الفتح/الإغلاق_. يمكنك تقديم وسطاء جدد دون الحاجة إلى تغيير المكوّنات الفعلية.
* يمكنك تقليل الاقتران بين المكوّنات المختلفة للبرنامج.
* يمكنك إعادة استخدام المكوّنات الفردية بشكل أسهل.

## Cons

* بمرور الوقت، قد يتطور الوسيط إلى [كائن إله](/ar/antipatterns/god-object).

## 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/facade) و[الوسيط](/ar/design-patterns/mediator) لهما وظائف مشابهة: يحاولان تنظيم التعاون بين الكثير من الفئات المترابطة بإحكام.

  * _الواجهة_ تُعرّف واجهة مبسّطة لنظام فرعي من الكائنات، لكنها لا تُقدّم أي وظائف جديدة. النظام الفرعي نفسه لا يعلم بوجود الواجهة. يمكن للكائنات داخل النظام الفرعي التواصل مباشرةً.
  * _الوسيط_ يُمركز التواصل بين مكوّنات النظام. المكوّنات تعرف فقط عن كائن الوسيط ولا تتواصل مباشرةً.
* الفارق بين [الوسيط](/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/observer.md)
- [الواجهة (Facade)](/ar/design-patterns/facade.md)

## Code Examples

### java

```java
package refactoring_guru.mediator.example.components;

import refactoring_guru.mediator.example.mediator.Mediator;

/**
 * واجهة المكوّن المشتركة.
 */
public interface Component {
    void setMediator(Mediator mediator);
    String getName();
}

package refactoring_guru.mediator.example.components;

import refactoring_guru.mediator.example.mediator.Mediator;
import refactoring_guru.mediator.example.mediator.Note;

import javax.swing.*;
import java.awt.event.ActionEvent;

/**
 * لا تتواصل المكوّنات الملموسة مع بعضها. لديها قناة تواصل واحدة فقط
 * وهي إرسال الطلبات إلى الوسيط.
 */
public class AddButton extends JButton implements Component {
    private Mediator mediator;

    public AddButton() {
        super("Add");
    }

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    @Override
    protected void fireActionPerformed(ActionEvent actionEvent) {
        mediator.addNewNote(new Note());
    }

    @Override
    public String getName() {
        return "AddButton";
    }
}

package refactoring_guru.mediator.example.components;

import refactoring_guru.mediator.example.mediator.Mediator;

import javax.swing.*;
import java.awt.event.ActionEvent;

/**
 * لا تتواصل المكوّنات الملموسة مع بعضها. لديها قناة تواصل واحدة فقط
 * وهي إرسال الطلبات إلى الوسيط.
 */
public class DeleteButton extends JButton  implements Component {
    private Mediator mediator;

    public DeleteButton() {
        super("Del");
    }

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    @Override
    protected void fireActionPerformed(ActionEvent actionEvent) {
        mediator.deleteNote();
    }

    @Override
    public String getName() {
        return "DelButton";
    }
}

package refactoring_guru.mediator.example.components;

import refactoring_guru.mediator.example.mediator.Mediator;
import refactoring_guru.mediator.example.mediator.Note;

import javax.swing.*;
import java.awt.event.KeyEvent;
import java.util.ArrayList;

/**
 * لا تتواصل المكوّنات الملموسة مع بعضها. لديها قناة تواصل واحدة فقط
 * وهي إرسال الطلبات إلى الوسيط.
 */
public class Filter extends JTextField implements Component {
    private Mediator mediator;
    private ListModel listModel;

    public Filter() {}

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    @Override
    protected void processComponentKeyEvent(KeyEvent keyEvent) {
        String start = getText();
        searchElements(start);
    }

    public void setList(ListModel listModel) {
        this.listModel = listModel;
    }

    private void searchElements(String s) {
        if (listModel == null) {
            return;
        }

        if (s.equals("")) {
            mediator.setElementsList(listModel);
            return;
        }

        ArrayList<Note> notes = new ArrayList<>();
        for (int i = 0; i < listModel.getSize(); i++) {
            notes.add((Note) listModel.getElementAt(i));
        }
        DefaultListModel<Note> listModel = new DefaultListModel<>();
        for (Note note : notes) {
            if (note.getName().contains(s)) {
                listModel.addElement(note);
            }
        }
        mediator.setElementsList(listModel);
    }

    @Override
    public String getName() {
        return "Filter";
    }
}

package refactoring_guru.mediator.example.components;

import refactoring_guru.mediator.example.mediator.Mediator;
import refactoring_guru.mediator.example.mediator.Note;

import javax.swing.*;

/**
 * لا تتواصل المكوّنات الملموسة مع بعضها. لديها قناة تواصل واحدة فقط
 * وهي إرسال الطلبات إلى الوسيط.
 */
@SuppressWarnings("unchecked")
public class List extends JList implements Component {
    private Mediator mediator;
    private final DefaultListModel LIST_MODEL;

    public List(DefaultListModel listModel) {
        super(listModel);
        this.LIST_MODEL = listModel;
        setModel(listModel);
        this.setLayoutOrientation(JList.VERTICAL);
        Thread thread = new Thread(new Hide(this));
        thread.start();
    }

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    public void addElement(Note note) {
        LIST_MODEL.addElement(note);
        int index = LIST_MODEL.size() - 1;
        setSelectedIndex(index);
        ensureIndexIsVisible(index);
        mediator.sendToFilter(LIST_MODEL);
    }

    public void deleteElement() {
        int index = this.getSelectedIndex();
        try {
            LIST_MODEL.remove(index);
            mediator.sendToFilter(LIST_MODEL);
        } catch (ArrayIndexOutOfBoundsException ignored) {}
    }

    public Note getCurrentElement() {
        return (Note)getSelectedValue();
    }

    @Override
    public String getName() {
        return "List";
    }

    private class Hide implements Runnable {
        private List list;

        Hide(List list) {
            this.list = list;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(300);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
                if (list.isSelectionEmpty()) {
                    mediator.hideElements(true);
                } else {
                    mediator.hideElements(false);
                }
            }
        }
    }
}

package refactoring_guru.mediator.example.components;

import refactoring_guru.mediator.example.mediator.Mediator;

import javax.swing.*;
import java.awt.event.ActionEvent;

/**
 * لا تتواصل المكوّنات الملموسة مع بعضها. لديها قناة تواصل واحدة فقط
 * وهي إرسال الطلبات إلى الوسيط.
 */
public class SaveButton extends JButton implements Component {
    private Mediator mediator;

    public SaveButton() {
        super("Save");
    }

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    @Override
    protected void fireActionPerformed(ActionEvent actionEvent) {
        mediator.saveChanges();
    }

    @Override
    public String getName() {
        return "SaveButton";
    }
}

package refactoring_guru.mediator.example.components;

import refactoring_guru.mediator.example.mediator.Mediator;

import javax.swing.*;
import java.awt.event.KeyEvent;

/**
 * لا تتواصل المكوّنات الملموسة مع بعضها. لديها قناة تواصل واحدة فقط
 * وهي إرسال الطلبات إلى الوسيط.
 */
public class TextBox extends JTextArea implements Component {
    private Mediator mediator;

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    @Override
    protected void processComponentKeyEvent(KeyEvent keyEvent) {
        mediator.markNote();
    }

    @Override
    public String getName() {
        return "TextBox";
    }
}

package refactoring_guru.mediator.example.components;

import refactoring_guru.mediator.example.mediator.Mediator;

import javax.swing.*;
import java.awt.event.KeyEvent;

/**
 * لا تتواصل المكوّنات الملموسة مع بعضها. لديها قناة تواصل واحدة فقط
 * وهي إرسال الطلبات إلى الوسيط.
 */
public class Title extends JTextField implements Component {
    private Mediator mediator;

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    @Override
    protected void processComponentKeyEvent(KeyEvent keyEvent) {
        mediator.markNote();
    }

    @Override
    public String getName() {
        return "Title";
    }
}

package refactoring_guru.mediator.example.mediator;

import refactoring_guru.mediator.example.components.Component;

import javax.swing.*;

/**
 * واجهة الوسيط المشتركة.
 */
public interface Mediator {
    void addNewNote(Note note);
    void deleteNote();
    void getInfoFromList(Note note);
    void saveChanges();
    void markNote();
    void clear();
    void sendToFilter(ListModel listModel);
    void setElementsList(ListModel list);
    void registerComponent(Component component);
    void hideElements(boolean flag);
    void createGUI();
}

package refactoring_guru.mediator.example.mediator;

import refactoring_guru.mediator.example.components.*;
import refactoring_guru.mediator.example.components.Component;
import refactoring_guru.mediator.example.components.List;

import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;

/**
 * الوسيط الملموس. جميع الاتصالات الفوضوية بين المكوّنات الملموسة
 * نُقلت إلى الوسيط. الآن تتحدث المكوّنات فقط مع الوسيط،
 * الذي يعرف من يجب عليه معالجة الطلب.
 */
public class Editor implements Mediator {
    private Title title;
    private TextBox textBox;
    private AddButton add;
    private DeleteButton del;
    private SaveButton save;
    private List list;
    private Filter filter;

    private JLabel titleLabel = new JLabel("Title:");
    private JLabel textLabel = new JLabel("Text:");
    private JLabel label = new JLabel("Add or select existing note to proceed...");
  
    /**
     * هنا يتم تسجيل المكوّنات بواسطة الوسيط.
     */
    @Override
    public void registerComponent(Component component) {
        component.setMediator(this);
        switch (component.getName()) {
            case "AddButton":
                add = (AddButton)component;
                break;
            case "DelButton":
                del = (DeleteButton)component;
                break;
            case "Filter":
                filter = (Filter)component;
                break;
            case "List":
                list = (List)component;
                this.list.addListSelectionListener(listSelectionEvent -> {
                    Note note = (Note)list.getSelectedValue();
                    if (note != null) {
                        getInfoFromList(note);
                    } else {
                        clear();
                    }
                });
                break;
            case "SaveButton":
                save = (SaveButton)component;
                break;
            case "TextBox":
                textBox = (TextBox)component;
                break;
            case "Title":
                title = (Title)component;
                break;
        }
    }

    /**
     * طرق متنوعة لمعالجة الطلبات من مكوّنات بعينها.
     */
    @Override
    public void addNewNote(Note note) {
        title.setText("");
        textBox.setText("");
        list.addElement(note);
    }

    @Override
    public void deleteNote() {
        list.deleteElement();
    }

    @Override
    public void getInfoFromList(Note note) {
        title.setText(note.getName().replace('*', ' '));
        textBox.setText(note.getText());
    }

    @Override
    public void saveChanges() {
        try {
            Note note = (Note) list.getSelectedValue();
            note.setName(title.getText());
            note.setText(textBox.getText());
            list.repaint();
        } catch (NullPointerException ignored) {}
    }

    @Override
    public void markNote() {
        try {
            Note note = list.getCurrentElement();
            String name = note.getName();
            if (!name.endsWith("*")) {
                note.setName(note.getName() + "*");
            }
            list.repaint();
        } catch (NullPointerException ignored) {}
    }

    @Override
    public void clear() {
        title.setText("");
        textBox.setText("");
    }

    @Override
    public void sendToFilter(ListModel listModel) {
        filter.setList(listModel);
    }

    @SuppressWarnings("unchecked")
    @Override
    public void setElementsList(ListModel list) {
        this.list.setModel(list);
        this.list.repaint();
    }

    @Override
    public void hideElements(boolean flag) {
        titleLabel.setVisible(!flag);
        textLabel.setVisible(!flag);
        title.setVisible(!flag);
        textBox.setVisible(!flag);
        save.setVisible(!flag);
        label.setVisible(flag);
    }

    @Override
    public void createGUI() {
        JFrame notes = new JFrame("Notes");
        notes.setSize(960, 600);
        notes.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        JPanel left = new JPanel();
        left.setBorder(new LineBorder(Color.BLACK));
        left.setSize(320, 600);
        left.setLayout(new BoxLayout(left, BoxLayout.Y_AXIS));
        JPanel filterPanel = new JPanel();
        filterPanel.add(new JLabel("Filter:"));
        filter.setColumns(20);
        filterPanel.add(filter);
        filterPanel.setPreferredSize(new Dimension(280, 40));
        JPanel listPanel = new JPanel();
        list.setFixedCellWidth(260);
        listPanel.setSize(320, 470);
        JScrollPane scrollPane = new JScrollPane(list);
        scrollPane.setPreferredSize(new Dimension(275, 410));
        listPanel.add(scrollPane);
        JPanel buttonPanel = new JPanel();
        add.setPreferredSize(new Dimension(85, 25));
        buttonPanel.add(add);
        del.setPreferredSize(new Dimension(85, 25));
        buttonPanel.add(del);
        buttonPanel.setLayout(new FlowLayout());
        left.add(filterPanel);
        left.add(listPanel);
        left.add(buttonPanel);
        JPanel right = new JPanel();
        right.setLayout(null);
        right.setSize(640, 600);
        right.setLocation(320, 0);
        right.setBorder(new LineBorder(Color.BLACK));
        titleLabel.setBounds(20, 4, 50, 20);
        title.setBounds(60, 5, 555, 20);
        textLabel.setBounds(20, 4, 50, 130);
        textBox.setBorder(new LineBorder(Color.DARK_GRAY));
        textBox.setBounds(20, 80, 595, 410);
        save.setBounds(270, 535, 80, 25);
        label.setFont(new Font("Verdana", Font.PLAIN, 22));
        label.setBounds(100, 240, 500, 100);
        right.add(label);
        right.add(titleLabel);
        right.add(title);
        right.add(textLabel);
        right.add(textBox);
        right.add(save);
        notes.setLayout(null);
        notes.getContentPane().add(left);
        notes.getContentPane().add(right);
        notes.setResizable(false);
        notes.setLocationRelativeTo(null);
        notes.setVisible(true);
    }
}

package refactoring_guru.mediator.example.mediator;

/**
 * فئة الملاحظة.
 */
public class Note {
    private String name;
    private String text;

    public Note() {
        name = "New note";
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getName() {
        return name;
    }

    public String getText() {
        return text;
    }

    @Override
    public String toString() {
        return name;
    }
}

package refactoring_guru.mediator.example;

import refactoring_guru.mediator.example.components.*;
import refactoring_guru.mediator.example.mediator.Editor;
import refactoring_guru.mediator.example.mediator.Mediator;

import javax.swing.*;

/**
 * فئة العرض التوضيحي. يجتمع كل شيء هنا.
 */
public class Demo {
    public static void main(String[] args) {
        Mediator mediator = new Editor();

        mediator.registerComponent(new Title());
        mediator.registerComponent(new TextBox());
        mediator.registerComponent(new AddButton());
        mediator.registerComponent(new DeleteButton());
        mediator.registerComponent(new SaveButton());
        mediator.registerComponent(new List(new DefaultListModel()));
        mediator.registerComponent(new Filter());

        mediator.createGUI();
    }
}
```

### csharp

```csharp
using System;

namespace RefactoringGuru.DesignPatterns.Mediator.Conceptual
{
    // تُعلن واجهة الوسيط عن طريقة تستخدمها المكوّنات لإخطار الوسيط
    // بأحداث متنوعة. قد يستجيب الوسيط لهذه الأحداث ويمرر
    // التنفيذ إلى مكوّنات أخرى.
    public interface IMediator
    {
        void Notify(object sender, string ev);
    }

    // تُنفّذ الوسطاء الملموسون سلوكاً تعاونياً بتنسيق عدة مكوّنات.
    class ConcreteMediator : IMediator
    {
        private Component1 _component1;

        private Component2 _component2;

        public ConcreteMediator(Component1 component1, Component2 component2)
        {
            this._component1 = component1;
            this._component1.SetMediator(this);
            this._component2 = component2;
            this._component2.SetMediator(this);
        } 

        public void Notify(object sender, string ev)
        {
            if (ev == "A")
            {
                Console.WriteLine("Mediator reacts on A and triggers following operations:");
                this._component2.DoC();
            }
            if (ev == "D")
            {
                Console.WriteLine("Mediator reacts on D and triggers following operations:");
                this._component1.DoB();
                this._component2.DoC();
            }
        }
    }

    // The Base Component provides the basic functionality of storing a
    // mediator's instance inside component objects.
    class BaseComponent
    {
        protected IMediator _mediator;

        public BaseComponent(IMediator mediator = null)
        {
            this._mediator = mediator;
        }

        public void SetMediator(IMediator mediator)
        {
            this._mediator = mediator;
        }
    }

    // تُنفّذ المكوّنات الملموسة وظائف متنوعة. لا تعتمد على
    // مكوّنات أخرى. كذلك لا تعتمد على أي فئات وسيط ملموسة.
    class Component1 : BaseComponent
    {
        public void DoA()
        {
            Console.WriteLine("Component 1 does A.");

            this._mediator.Notify(this, "A");
        }

        public void DoB()
        {
            Console.WriteLine("Component 1 does B.");

            this._mediator.Notify(this, "B");
        }
    }

    class Component2 : BaseComponent
    {
        public void DoC()
        {
            Console.WriteLine("Component 2 does C.");

            this._mediator.Notify(this, "C");
        }

        public void DoD()
        {
            Console.WriteLine("Component 2 does D.");

            this._mediator.Notify(this, "D");
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            // كود العميل.
            Component1 component1 = new Component1();
            Component2 component2 = new Component2();
            new ConcreteMediator(component1, component2);

            Console.WriteLine("Client triggers operation A.");
            component1.DoA();

            Console.WriteLine();

            Console.WriteLine("Client triggers operation D.");
            component2.DoD();
        }
    }
}

Client triggers operation A.
Component 1 does A.
Mediator reacts on A and triggers following operations:
Component 2 does C.

Client triggers operation D.
Component 2 does D.
Mediator reacts on D and triggers following operations:
Component 1 does B.
Component 2 does C.
```

### cpp

```cpp
#include <iostream>
#include <string>
/**
 * تُعلن واجهة الوسيط عن طريقة تستخدمها المكوّنات لإخطار الوسيط
 * بأحداث متنوعة. قد يستجيب الوسيط لهذه الأحداث ويمرر
 * التنفيذ إلى مكوّنات أخرى.
 */
class BaseComponent;
class Mediator {
 public:
  virtual void Notify(BaseComponent *sender, std::string event) const = 0;
};

/**
 * يوفر المكوّن الأساسي وظيفة تخزين نسخة الوسيط
 * داخل كائنات المكوّنات.
 */
class BaseComponent {
 protected:
  Mediator *mediator_;

 public:
  BaseComponent(Mediator *mediator = nullptr) : mediator_(mediator) {
  }
  void set_mediator(Mediator *mediator) {
    this->mediator_ = mediator;
  }
};

/**
 * تُنفّذ المكوّنات الملموسة وظائف متنوعة. لا تعتمد على
 * مكوّنات أخرى. كذلك لا تعتمد على أي فئات وسيط ملموسة.
 */
class Component1 : public BaseComponent {
 public:
  void DoA() {
    std::cout << "Component 1 does A.\n";
    this->mediator_->Notify(this, "A");
  }
  void DoB() {
    std::cout << "Component 1 does B.\n";
    this->mediator_->Notify(this, "B");
  }
};

class Component2 : public BaseComponent {
 public:
  void DoC() {
    std::cout << "Component 2 does C.\n";
    this->mediator_->Notify(this, "C");
  }
  void DoD() {
    std::cout << "Component 2 does D.\n";
    this->mediator_->Notify(this, "D");
  }
};

/**
 * تُنفّذ الوسطاء الملموسون سلوكاً تعاونياً بتنسيق عدة مكوّنات.
 */
class ConcreteMediator : public Mediator {
 private:
  Component1 *component1_;
  Component2 *component2_;

 public:
  ConcreteMediator(Component1 *c1, Component2 *c2) : component1_(c1), component2_(c2) {
    this->component1_->set_mediator(this);
    this->component2_->set_mediator(this);
  }
  void Notify(BaseComponent *sender, std::string event) const override {
    if (event == "A") {
      std::cout << "Mediator reacts on A and triggers following operations:\n";
      this->component2_->DoC();
    }
    if (event == "D") {
      std::cout << "Mediator reacts on D and triggers following operations:\n";
      this->component1_->DoB();
      this->component2_->DoC();
    }
  }
};

/**
 * كود العميل.
 */

void ClientCode() {
  Component1 *c1 = new Component1;
  Component2 *c2 = new Component2;
  ConcreteMediator *mediator = new ConcreteMediator(c1, c2);
  std::cout << "Client triggers operation A.\n";
  c1->DoA();
  std::cout << "\n";
  std::cout << "Client triggers operation D.\n";
  c2->DoD();

  delete c1;
  delete c2;
  delete mediator;
}

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

Client triggers operation A.
Component 1 does A.
Mediator reacts on A and triggers following operations:
Component 2 does C.

Client triggers operation D.
Component 2 does D.
Mediator reacts on D and triggers following operations:
Component 1 does B.
Component 2 does C.
```

### go

```go
package main

type Train interface {
	arrive()
	depart()
	permitArrival()
}

package main

import "fmt"

type PassengerTrain struct {
	mediator Mediator
}

func (g *PassengerTrain) arrive() {
	if !g.mediator.canArrive(g) {
		fmt.Println("PassengerTrain: Arrival blocked, waiting")
		return
	}
	fmt.Println("PassengerTrain: Arrived")
}

func (g *PassengerTrain) depart() {
	fmt.Println("PassengerTrain: Leaving")
	g.mediator.notifyAboutDeparture()
}

func (g *PassengerTrain) permitArrival() {
	fmt.Println("PassengerTrain: Arrival permitted, arriving")
	g.arrive()
}

package main

import "fmt"

type FreightTrain struct {
	mediator Mediator
}

func (g *FreightTrain) arrive() {
	if !g.mediator.canArrive(g) {
		fmt.Println("FreightTrain: Arrival blocked, waiting")
		return
	}
	fmt.Println("FreightTrain: Arrived")
}

func (g *FreightTrain) depart() {
	fmt.Println("FreightTrain: Leaving")
	g.mediator.notifyAboutDeparture()
}

func (g *FreightTrain) permitArrival() {
	fmt.Println("FreightTrain: Arrival permitted")
	g.arrive()
}

package main

type Mediator interface {
	canArrive(Train) bool
	notifyAboutDeparture()
}

package main

type StationManager struct {
	isPlatformFree bool
	trainQueue     []Train
}

func newStationManger() *StationManager {
	return &StationManager{
		isPlatformFree: true,
	}
}

func (s *StationManager) canArrive(t Train) bool {
	if s.isPlatformFree {
		s.isPlatformFree = false
		return true
	}
	s.trainQueue = append(s.trainQueue, t)
	return false
}

func (s *StationManager) notifyAboutDeparture() {
	if !s.isPlatformFree {
		s.isPlatformFree = true
	}
	if len(s.trainQueue) > 0 {
		firstTrainInQueue := s.trainQueue[0]
		s.trainQueue = s.trainQueue[1:]
		firstTrainInQueue.permitArrival()
	}
}

package main

func main() {
	stationManager := newStationManger()

	passengerTrain := &PassengerTrain{
		mediator: stationManager,
	}
	freightTrain := &FreightTrain{
		mediator: stationManager,
	}

	passengerTrain.arrive()
	freightTrain.arrive()
	passengerTrain.depart()
}

PassengerTrain: Arrived
FreightTrain: Arrival blocked, waiting
PassengerTrain: Leaving
FreightTrain: Arrival permitted
FreightTrain: Arrived
```

### php

```php
<?php

namespace RefactoringGuru\Mediator\Conceptual;

/**
 * تُعلن واجهة الوسيط عن طريقة تستخدمها المكوّنات لإخطار الوسيط
 * بأحداث متنوعة. قد يستجيب الوسيط لهذه الأحداث ويمرر
 * التنفيذ إلى مكوّنات أخرى.
 */
interface Mediator
{
    public function notify(object $sender, string $event): void;
}

/**
 * تُنفّذ الوسطاء الملموسون سلوكاً تعاونياً بتنسيق عدة مكوّنات.
 */
class ConcreteMediator implements Mediator
{
    private $component1;

    private $component2;

    public function __construct(Component1 $c1, Component2 $c2)
    {
        $this->component1 = $c1;
        $this->component1->setMediator($this);
        $this->component2 = $c2;
        $this->component2->setMediator($this);
    }

    public function notify(object $sender, string $event): void
    {
        if ($event == "A") {
            echo "Mediator reacts on A and triggers following operations:\n";
            $this->component2->doC();
        }

        if ($event == "D") {
            echo "Mediator reacts on D and triggers following operations:\n";
            $this->component1->doB();
            $this->component2->doC();
        }
    }
}

/**
 * يوفر المكوّن الأساسي وظيفة تخزين نسخة الوسيط
 * داخل كائنات المكوّنات.
 */
class BaseComponent
{
    protected $mediator;

    public function __construct(Mediator $mediator = null)
    {
        $this->mediator = $mediator;
    }

    public function setMediator(Mediator $mediator): void
    {
        $this->mediator = $mediator;
    }
}

/**
 * تُنفّذ المكوّنات الملموسة وظائف متنوعة. لا تعتمد على
 * مكوّنات أخرى. كذلك لا تعتمد على أي فئات وسيط ملموسة.
 */
class Component1 extends BaseComponent
{
    public function doA(): void
    {
        echo "Component 1 does A.\n";
        $this->mediator->notify($this, "A");
    }

    public function doB(): void
    {
        echo "Component 1 does B.\n";
        $this->mediator->notify($this, "B");
    }
}

class Component2 extends BaseComponent
{
    public function doC(): void
    {
        echo "Component 2 does C.\n";
        $this->mediator->notify($this, "C");
    }

    public function doD(): void
    {
        echo "Component 2 does D.\n";
        $this->mediator->notify($this, "D");
    }
}

/**
 * كود العميل.
 */
$c1 = new Component1();
$c2 = new Component2();
$mediator = new ConcreteMediator($c1, $c2);

echo "Client triggers operation A.\n";
$c1->doA();

echo "\n";
echo "Client triggers operation D.\n";
$c2->doD();

Client triggers operation A.
Component 1 does A.
Mediator reacts on A and triggers following operations:
Component 2 does C.

Client triggers operation D.
Component 2 does D.
Mediator reacts on D and triggers following operations:
Component 1 does B.
Component 2 does C.

<?php

namespace RefactoringGuru\Mediator\RealWorld;

/**
 * يعمل الـ EventDispatcher كوسيط ويحتوي على منطق الاشتراك والإشعار.
 * في حين يعتمد الوسيط الكلاسيكي غالباً على فئات المكوّنات الملموسة،
 * هذا مرتبط فقط بواجهاتها المجردة.
 *
 * نستطيع تحقيق هذا المستوى من التجريد بفضل الطريقة التي
 * تُنشأ بها الاتصالات بين المكوّنات. قد يشترك المكوّنون أنفسهم
 * في أحداث محددة تهمهم عبر واجهة الاشتراك الخاصة بالوسيط.
 *
 * ملاحظة: لا يمكننا استخدام واجهتي Subject/Observer المدمجتين في PHP
 * لأننا سنمتدهما بعيداً عما صُممتا من أجله.
 */
class EventDispatcher
{
    /**
     * @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(Observer $observer, string $event = "*"): void
    {
        $this->initEventGroup($event);

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

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

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

/**
 * دالة مساعدة بسيطة لتوفير وصول عالمي لموزّع الأحداث.
 */
function events(): EventDispatcher
{
    static $eventDispatcher;
    if (!$eventDispatcher) {
        $eventDispatcher = new EventDispatcher();
    }

    return $eventDispatcher;
}

/**
 * تُعرّف واجهة المراقب كيفية استقبال المكوّنات لإشعارات الأحداث.
 */
interface Observer
{
    public function update(string $event, object $emitter, $data = null);
}

/**
 * على عكس مثال نمط المراقب لدينا، يجعل هذا المثال UserRepository
 * يعمل كمكوّن عادي لا يمتلك أي طرق خاصة بالأحداث. كأي مكوّن آخر،
 * تعتمد هذه الفئة على EventDispatcher لبث أحداثها والاستماع للأحداث الأخرى.
 *
 * @see \RefactoringGuru\Observer\RealWorld\UserRepository
 */
class UserRepository implements Observer
{
    /**
     * @var array قائمة مستخدمي التطبيق.
     */
    private $users = [];

    /**
     * يمكن للمكوّنات الاشتراك في الأحداث بنفسها أو عبر كود العميل.
     */
    public function __construct()
    {
        events()->attach($this, "users:deleted");
    }

    /**
     * يمكن للمكوّنات أن تقرر ما إذا كانت تريد معالجة حدث ما باستخدام
     * اسمه أو المُرسِل أو أي بيانات سياقية مُمرَّرة مع الحدث.
     */
    public function update(string $event, object $emitter, $data = null): void
    {
        switch ($event) {
            case "users:deleted":
                if ($emitter === $this) {
                    return;
                }
                $this->deleteUser($data, true);
                break;
        }
    }

    // تمثل هذه الطرق منطق الأعمال للفئة.

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

    public function createUser(array $data, bool $silent = false): 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;

        if (!$silent) {
            events()->trigger("users:created", $this, $user);
        }

        return $user;
    }

    public function updateUser(User $user, array $data, bool $silent = false): ?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);

        if (!$silent) {
            events()->trigger("users:updated", $this, $user);
        }

        return $user;
    }

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

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

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

        if (!$silent) {
            events()->trigger("users:deleted", $this, $user);
        }
    }
}

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

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

    /**
     * يمكن لجميع الكائنات إطلاق الأحداث.
     */
    public function delete(): void
    {
        echo "User: I can now delete myself without worrying about the repository.\n";
        events()->trigger("users:deleted", $this, $this);
    }
}

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

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

    public function update(string $event, object $emitter, $data = null)
    {
        $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 Observer
{
    private $adminEmail;

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

    public function update(string $event, object $emitter, $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();
events()->attach($repository, "facebook:update");

$logger = new Logger(__DIR__ . "/log.txt");
events()->attach($logger, "*");

$onboarding = new OnboardingNotification("1@example.com");
events()->attach($onboarding, "users:created");

// ...

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

// ...

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

// ...

$user->delete();

UserRepository: Loading user records from a file.
EventDispatcher: Broadcasting the 'users:init' event.
Logger: I've written 'users:init' entry to the log.
UserRepository: Creating a user.
EventDispatcher: Broadcasting the 'users:created' event.
OnboardingNotification: The notification has been emailed!
Logger: I've written 'users:created' entry to the log.
User: I can now delete myself without worrying about the repository.
EventDispatcher: Broadcasting the 'users:deleted' event.
UserRepository: Deleting a user.
Logger: I've written 'users:deleted' entry to the log.
```

### python

```python
from __future__ import annotations
from abc import ABC


class Mediator(ABC):
    """
    تُعلن واجهة الوسيط عن طريقة تستخدمها المكوّنات لإخطار الوسيط
    بأحداث متنوعة. قد يستجيب الوسيط لهذه الأحداث ويمرر
    التنفيذ إلى مكوّنات أخرى.
    """

    def notify(self, sender: object, event: str) -> None:
        pass


class ConcreteMediator(Mediator):
    def __init__(self, component1: Component1, component2: Component2) -> None:
        self._component1 = component1
        self._component1.mediator = self
        self._component2 = component2
        self._component2.mediator = self

    def notify(self, sender: object, event: str) -> None:
        if event == "A":
            print("Mediator reacts on A and triggers following operations:")
            self._component2.do_c()
        elif event == "D":
            print("Mediator reacts on D and triggers following operations:")
            self._component1.do_b()
            self._component2.do_c()


class BaseComponent:
    """
    يوفر المكوّن الأساسي وظيفة تخزين نسخة الوسيط
    داخل كائنات المكوّنات.
    """

    def __init__(self, mediator: Mediator = None) -> None:
        self._mediator = mediator

    @property
    def mediator(self) -> Mediator:
        return self._mediator

    @mediator.setter
    def mediator(self, mediator: Mediator) -> None:
        self._mediator = mediator


"""
تُنفّذ المكوّنات الملموسة وظائف متنوعة. لا تعتمد على
مكوّنات أخرى. كذلك لا تعتمد على أي فئات وسيط ملموسة.
"""


class Component1(BaseComponent):
    def do_a(self) -> None:
        print("Component 1 does A.")
        self.mediator.notify(self, "A")

    def do_b(self) -> None:
        print("Component 1 does B.")
        self.mediator.notify(self, "B")


class Component2(BaseComponent):
    def do_c(self) -> None:
        print("Component 2 does C.")
        self.mediator.notify(self, "C")

    def do_d(self) -> None:
        print("Component 2 does D.")
        self.mediator.notify(self, "D")


if __name__ == "__main__":
    # كود العميل.
    c1 = Component1()
    c2 = Component2()
    mediator = ConcreteMediator(c1, c2)

    print("Client triggers operation A.")
    c1.do_a()

    print("\n", end="")

    print("Client triggers operation D.")
    c2.do_d()

Client triggers operation A.
Component 1 does A.
Mediator reacts on A and triggers following operations:
Component 2 does C.


Client triggers operation D.
Component 2 does D.
Mediator reacts on D and triggers following operations:
Component 1 does B.
Component 2 does C.
```

### ruby

```ruby
# تُعلن واجهة الوسيط عن طريقة تستخدمها المكوّنات لإخطار الوسيط
# بأحداث متنوعة. قد يستجيب الوسيط لهذه الأحداث ويمرر
# التنفيذ إلى مكوّنات أخرى.
class Mediator
  # @abstract
  #
  # @param [Object] sender
  # @param [String] event
  def notify(_sender, _event)
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end

class ConcreteMediator < Mediator
  # @param [Component1] component1
  # @param [Component2] component2
  def initialize(component1, component2)
    @component1 = component1
    @component1.mediator = self
    @component2 = component2
    @component2.mediator = self
  end

  # @param [Object] sender
  # @param [String] event
  def notify(_sender, event)
    if event == 'A'
      puts 'Mediator reacts on A and triggers following operations:'
      @component2.do_c
    elsif event == 'D'
      puts 'Mediator reacts on D and triggers following operations:'
      @component1.do_b
      @component2.do_c
    end
  end
end

# يوفر المكوّن الأساسي وظيفة تخزين نسخة الوسيط
# داخل كائنات المكوّنات.
class BaseComponent
  # @return [Mediator]
  attr_accessor :mediator

  # @param [Mediator] mediator
  def initialize(mediator = nil)
    @mediator = mediator
  end
end

# تُنفّذ المكوّنات الملموسة وظائف متنوعة. لا تعتمد على
# مكوّنات أخرى. كذلك لا تعتمد على أي فئات وسيط ملموسة.
class Component1 < BaseComponent
  def do_a
    puts 'Component 1 does A.'
    @mediator.notify(self, 'A')
  end

  def do_b
    puts 'Component 1 does B.'
    @mediator.notify(self, 'B')
  end
end

class Component2 < BaseComponent
  def do_c
    puts 'Component 2 does C.'
    @mediator.notify(self, 'C')
  end

  def do_d
    puts 'Component 2 does D.'
    @mediator.notify(self, 'D')
  end
end

# كود العميل.
c1 = Component1.new
c2 = Component2.new
ConcreteMediator.new(c1, c2)

puts 'Client triggers operation A.'
c1.do_a

puts "\n"

puts 'Client triggers operation D.'
c2.do_d

Client triggers operation A.
Component 1 does A.
Mediator reacts on A and triggers following operations:
Component 2 does C.

Client triggers operation D.
Component 2 does D.
Mediator reacts on D and triggers following operations:
Component 1 does B.
Component 2 does C.
```

### rust

```rust
// يحصل القطار على كائن الوسيط بالإشارة (مرجع).
pub trait Train {
    fn name(&self) -> &String;
    fn arrive(&mut self, mediator: &mut dyn Mediator);
    fn depart(&mut self, mediator: &mut dyn Mediator);
}

// يمتلك الوسيط طرق إشعار.
pub trait Mediator {
    fn notify_about_arrival(&mut self, train_name: &str) -> bool;
    fn notify_about_departure(&mut self, train_name: &str);
}

let train1 = PassengerTrain::new("Train 1");
let train2 = FreightTrain::new("Train 2");

// Station has `accept` and `depart` methods,
// but it also implements `Mediator`.
let mut station = TrainStation::default();

// Station is taking ownership of the trains.
station.accept(train1);
station.accept(train2);

// `train1` and `train2` have been moved inside,
// but we can use train names to depart them.
station.depart("Train 1");
station.depart("Train 2");
station.depart("Train 3");

use std::collections::{HashMap, VecDeque};

use crate::trains::Train;

// يمتلك الوسيط طرق إشعار.
pub trait Mediator {
    fn notify_about_arrival(&mut self, train_name: &str) -> bool;
    fn notify_about_departure(&mut self, train_name: &str);
}

#[derive(Default)]
pub struct TrainStation {
    trains: HashMap<String, Box<dyn Train>>,
    train_queue: VecDeque<String>,
    train_on_platform: Option<String>,
}

impl Mediator for TrainStation {
    fn notify_about_arrival(&mut self, train_name: &str) -> bool {
        if self.train_on_platform.is_some() {
            self.train_queue.push_back(train_name.into());
            false
        } else {
            self.train_on_platform.replace(train_name.into());
            true
        }
    }

    fn notify_about_departure(&mut self, train_name: &str) {
        if Some(train_name.into()) == self.train_on_platform {
            self.train_on_platform = None;

            if let Some(next_train_name) = self.train_queue.pop_front() {
                let mut next_train = self.trains.remove(&next_train_name).unwrap();
                next_train.arrive(self);
                self.trains.insert(next_train_name.clone(), next_train);

                self.train_on_platform = Some(next_train_name);
            }
        }
    }
}

impl TrainStation {
    pub fn accept(&mut self, mut train: impl Train + 'static) {
        if self.trains.contains_key(train.name()) {
            println!("{} has already arrived", train.name());
            return;
        }

        train.arrive(self);
        self.trains.insert(train.name().clone(), Box::new(train));
    }

    pub fn depart(&mut self, name: &'static str) {
        let train = self.trains.remove(name);
        if let Some(mut train) = train {
            train.depart(self);
        } else {
            println!("'{}' is not on the station!", name);
        }
    }
}

mod freight_train;
mod passenger_train;

pub use freight_train::FreightTrain;
pub use passenger_train::PassengerTrain;

use crate::train_station::Mediator;

// يحصل القطار على كائن الوسيط بالإشارة (مرجع).
pub trait Train {
    fn name(&self) -> &String;
    fn arrive(&mut self, mediator: &mut dyn Mediator);
    fn depart(&mut self, mediator: &mut dyn Mediator);
}

use super::Train;
use crate::train_station::Mediator;

pub struct FreightTrain {
    name: String,
}

impl FreightTrain {
    pub fn new(name: &'static str) -> Self {
        Self { name: name.into() }
    }
}

impl Train for FreightTrain {
    fn name(&self) -> &String {
        &self.name
    }

    fn arrive(&mut self, mediator: &mut dyn Mediator) {
        if !mediator.notify_about_arrival(&self.name) {
            println!("Freight train {}: Arrival blocked, waiting", self.name);
            return;
        }

        println!("Freight train {}: Arrived", self.name);
    }

    fn depart(&mut self, mediator: &mut dyn Mediator) {
        println!("Freight train {}: Leaving", self.name);
        mediator.notify_about_departure(&self.name);
    }
}

use super::Train;
use crate::train_station::Mediator;

pub struct PassengerTrain {
    name: String,
}

impl PassengerTrain {
    pub fn new(name: &'static str) -> Self {
        Self { name: name.into() }
    }
}

impl Train for PassengerTrain {
    fn name(&self) -> &String {
        &self.name
    }

    fn arrive(&mut self, mediator: &mut dyn Mediator) {
        if !mediator.notify_about_arrival(&self.name) {
            println!("Passenger train {}: Arrival blocked, waiting", self.name);
            return;
        }

        println!("Passenger train {}: Arrived", self.name);
    }

    fn depart(&mut self, mediator: &mut dyn Mediator) {
        println!("Passenger train {}: Leaving", self.name);
        mediator.notify_about_departure(&self.name);
    }
}

mod train_station;
mod trains;

use train_station::TrainStation;
use trains::{FreightTrain, PassengerTrain};

fn main() {
    let train1 = PassengerTrain::new("Train 1");
    let train2 = FreightTrain::new("Train 2");

    // تمتلك المحطة طريقتي `accept` و`depart`،
    // لكنها أيضاً تُنفّذ `Mediator`.
    let mut station = TrainStation::default();

    // تأخذ المحطة ملكية القطارات.
    station.accept(train1);
    station.accept(train2);

    // انتقل `train1` و`train2` إلى الداخل،
    // لكن يمكننا استخدام أسماء القطارات لإقلاعها.
    station.depart("Train 1");
    station.depart("Train 2");
    station.depart("Train 3");
}

Passenger train Train 1: Arrived
Freight train Train 2: Arrival blocked, waiting
Passenger train Train 1: Leaving
Freight train Train 2: Arrived
Freight train Train 2: Leaving
'Train 3' is not on the station!
```

### swift

```swift
import XCTest

/// تُعلن واجهة الوسيط عن طريقة تستخدمها المكوّنات لإخطار الوسيط
/// بأحداث متنوعة. قد يستجيب الوسيط لهذه الأحداث ويمرر
/// التنفيذ إلى مكوّنات أخرى.
protocol Mediator: AnyObject {

    func notify(sender: BaseComponent, event: String)
}

/// تُنفّذ الوسطاء الملموسون سلوكاً تعاونياً بتنسيق عدة مكوّنات.
class ConcreteMediator: Mediator {

    private var component1: Component1
    private var component2: Component2

    init(_ component1: Component1, _ component2: Component2) {
        self.component1 = component1
        self.component2 = component2

        component1.update(mediator: self)
        component2.update(mediator: self)
    }

    func notify(sender: BaseComponent, event: String) {
        if event == "A" {
            print("Mediator reacts on A and triggers following operations:")
            self.component2.doC()
        }
        else if (event == "D") {
            print("Mediator reacts on D and triggers following operations:")
            self.component1.doB()
            self.component2.doC()
        }
    }
}

/// يوفر المكوّن الأساسي وظيفة تخزين نسخة الوسيط
/// داخل كائنات المكوّنات.
class BaseComponent {

    fileprivate weak var mediator: Mediator?

    init(mediator: Mediator? = nil) {
        self.mediator = mediator
    }

    func update(mediator: Mediator) {
        self.mediator = mediator
    }
}

/// تُنفّذ المكوّنات الملموسة وظائف متنوعة. لا تعتمد على
/// مكوّنات أخرى. كذلك لا تعتمد على أي فئات وسيط ملموسة.
class Component1: BaseComponent {

    func doA() {
        print("Component 1 does A.")
        mediator?.notify(sender: self, event: "A")
    }

    func doB() {
        print("Component 1 does B.\n")
        mediator?.notify(sender: self, event: "B")
    }
}

class Component2: BaseComponent {

    func doC() {
        print("Component 2 does C.")
        mediator?.notify(sender: self, event: "C")
    }

    func doD() {
        print("Component 2 does D.")
        mediator?.notify(sender: self, event: "D")
    }
}

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

    func testMediatorConceptual() {

        let component1 = Component1()
        let component2 = Component2()

        let mediator = ConcreteMediator(component1, component2)
        print("Client triggers operation A.")
        component1.doA()

        print("\nClient triggers operation D.")
        component2.doD()

        print(mediator)
    }
}

Client triggers operation A.
Component 1 does A.
Mediator reacts on A and triggers following operations:
Component 2 does C.

Client triggers operation D.
Component 2 does D.
Mediator reacts on D and triggers following operations:
Component 1 does B.

Component 2 does C.

import XCTest

class MediatorRealWorld: XCTestCase {

    func test() {

        let newsArray = [News(id: 1, title: "News1", likesCount: 1),
                         News(id: 2, title: "News2", likesCount: 2)]

        let numberOfGivenLikes = newsArray.reduce(0, { $0 + $1.likesCount })

        let mediator = ScreenMediator()

        let feedVC = NewsFeedViewController(mediator, newsArray)
        let newsDetailVC = NewsDetailViewController(mediator, newsArray.first!)
        let profileVC = ProfileViewController(mediator, numberOfGivenLikes)

        mediator.update([feedVC, newsDetailVC, profileVC])

        feedVC.userLikedAllNews()
        feedVC.userDislikedAllNews()
    }
}

class NewsFeedViewController: ScreenUpdatable {

    private var newsArray: [News]
    private weak var mediator: ScreenUpdatable?

    init(_ mediator: ScreenUpdatable?, _ newsArray: [News]) {
        self.newsArray = newsArray
        self.mediator = mediator
    }

    func likeAdded(to news: News) {

        print("News Feed: Received a liked news model with id \(news.id)")

        for var item in newsArray {
            if item == news {
                item.likesCount += 1
            }
        }
    }

    func likeRemoved(from news: News) {

        print("News Feed: Received a disliked news model with id \(news.id)")

        for var item in newsArray {
            if item == news {
                item.likesCount -= 1
            }
        }
    }

    func userLikedAllNews() {
        print("\n\nNews Feed: User LIKED all news models")
        print("News Feed: I am telling to mediator about it...\n")
        newsArray.forEach({ mediator?.likeAdded(to: $0) })
    }

    func userDislikedAllNews() {
        print("\n\nNews Feed: User DISLIKED all news models")
        print("News Feed: I am telling to mediator about it...\n")
        newsArray.forEach({ mediator?.likeRemoved(from: $0) })
    }
}

class NewsDetailViewController: ScreenUpdatable {

    private var news: News
    private weak var mediator: ScreenUpdatable?

    init(_ mediator: ScreenUpdatable?, _ news: News) {
        self.news = news
        self.mediator = mediator
    }

    func likeAdded(to news: News) {
        print("News Detail: Received a liked news model with id \(news.id)")
        if self.news == news {
            self.news.likesCount += 1
        }
    }

    func likeRemoved(from news: News) {
        print("News Detail: Received a disliked news model with id \(news.id)")
        if self.news == news {
            self.news.likesCount -= 1
        }
    }
}

class ProfileViewController: ScreenUpdatable {

    private var numberOfGivenLikes: Int
    private weak var mediator: ScreenUpdatable?

    init(_ mediator: ScreenUpdatable?, _ numberOfGivenLikes: Int) {
        self.numberOfGivenLikes = numberOfGivenLikes
        self.mediator = mediator
    }

    func likeAdded(to news: News) {
        print("Profile: Received a liked news model with id \(news.id)")
        numberOfGivenLikes += 1
    }

    func likeRemoved(from news: News) {
        print("Profile: Received a disliked news model with id \(news.id)")
        numberOfGivenLikes -= 1
    }
}

protocol ScreenUpdatable: class {

    func likeAdded(to news: News)

    func likeRemoved(from news: News)
}

class ScreenMediator: ScreenUpdatable {

    private var screens: [ScreenUpdatable]?

    func update(_ screens: [ScreenUpdatable]) {
        self.screens = screens
    }

    func likeAdded(to news: News) {
        print("Screen Mediator: Received a liked news model with id \(news.id)")
        screens?.forEach({ $0.likeAdded(to: news) })
    }

    func likeRemoved(from news: News) {
        print("ScreenMediator: Received a disliked news model with id \(news.id)")
        screens?.forEach({ $0.likeRemoved(from: news) })
    }
}

struct News: Equatable {

    let id: Int

    let title: String

    var likesCount: Int

    /// Other properties

    static func == (left: News, right: News) -> Bool {
        return left.id == right.id
    }
}

News Feed: User LIKED all news models
News Feed: I am telling to mediator about it...

Screen Mediator: Received a liked news model with id 1
News Feed: Received a liked news model with id 1
News Detail: Received a liked news model with id 1
Profile: Received a liked news model with id 1
Screen Mediator: Received a liked news model with id 2
News Feed: Received a liked news model with id 2
News Detail: Received a liked news model with id 2
Profile: Received a liked news model with id 2


News Feed: User DISLIKED all news models
News Feed: I am telling to mediator about it...

ScreenMediator: Received a disliked news model with id 1
News Feed: Received a disliked news model with id 1
News Detail: Received a disliked news model with id 1
Profile: Received a disliked news model with id 1
ScreenMediator: Received a disliked news model with id 2
News Feed: Received a disliked news model with id 2
News Detail: Received a disliked news model with id 2
Profile: Received a disliked news model with id 2
```

### typescript

```typescript
/**
 * تُعلن واجهة الوسيط عن طريقة تستخدمها المكوّنات لإخطار الوسيط
 * بأحداث متنوعة. قد يستجيب الوسيط لهذه الأحداث ويمرر
 * التنفيذ إلى مكوّنات أخرى.
 */
interface Mediator {
    notify(sender: object, event: string): void;
}

/**
 * تُنفّذ الوسطاء الملموسون سلوكاً تعاونياً بتنسيق عدة مكوّنات.
 */
class ConcreteMediator implements Mediator {
    private component1: Component1;

    private component2: Component2;

    constructor(c1: Component1, c2: Component2) {
        this.component1 = c1;
        this.component1.setMediator(this);
        this.component2 = c2;
        this.component2.setMediator(this);
    }

    public notify(sender: object, event: string): void {
        if (event === 'A') {
            console.log('Mediator reacts on A and triggers following operations:');
            this.component2.doC();
        }

        if (event === 'D') {
            console.log('Mediator reacts on D and triggers following operations:');
            this.component1.doB();
            this.component2.doC();
        }
    }
}

/**
 * يوفر المكوّن الأساسي وظيفة تخزين نسخة الوسيط
 * داخل كائنات المكوّنات.
 */
class BaseComponent {
    protected mediator: Mediator;

    constructor(mediator?: Mediator) {
        this.mediator = mediator!;
    }

    public setMediator(mediator: Mediator): void {
        this.mediator = mediator;
    }
}

/**
 * تُنفّذ المكوّنات الملموسة وظائف متنوعة. لا تعتمد على
 * مكوّنات أخرى. كذلك لا تعتمد على أي فئات وسيط ملموسة.
 */
class Component1 extends BaseComponent {
    public doA(): void {
        console.log('Component 1 does A.');
        this.mediator.notify(this, 'A');
    }

    public doB(): void {
        console.log('Component 1 does B.');
        this.mediator.notify(this, 'B');
    }
}

class Component2 extends BaseComponent {
    public doC(): void {
        console.log('Component 2 does C.');
        this.mediator.notify(this, 'C');
    }

    public doD(): void {
        console.log('Component 2 does D.');
        this.mediator.notify(this, 'D');
    }
}

/**
 * كود العميل.
 */
const c1 = new Component1();
const c2 = new Component2();
const mediator = new ConcreteMediator(c1, c2);

console.log('Client triggers operation A.');
c1.doA();

console.log('');
console.log('Client triggers operation D.');
c2.doD();

Client triggers operation A.
Component 1 does A.
Mediator reacts on A and triggers following operations:
Component 2 does C.

Client triggers operation D.
Component 2 does D.
Mediator reacts on D and triggers following operations:
Component 1 does B.
Component 2 does C.
```

