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

> Singleton (النمط الفردي) هو نمط تصميم إنشائي يتيح لك ضمان أن الصنف لديه نسخة واحدة فقط، مع توفير نقطة وصول عالمية لهذه النسخة.

## Intent

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

## Problem

يحل نمط Singleton مشكلتين في آنٍ واحد، مما ينتهك _مبدأ المسؤولية الواحدة_:

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

Clients may not even realize that they’re working with the same object all the time.

1. **توفير نقطة وصول عالمية لتلك النسخة**. تذكر تلك المتغيرات العالمية التي استخدمتها (حسناً، أنا) لتخزين بعض الكائنات الأساسية؟ رغم أنها مفيدة جداً، إلا أنها غير آمنة للغاية، إذ يمكن لأي كود احتمال الكتابة فوق محتويات تلك المتغيرات وتعطيل التطبيق.
تماماً كالمتغير العالمي، يتيح لك نمط Singleton الوصول إلى كائن ما من أي مكان في البرنامج. غير أنه يحمي تلك النسخة أيضاً من الكتابة فوقها من قِبَل كود آخر.
ثمة جانب آخر لهذه المشكلة: لا تريد أن يتناثر الكود الذي يحل المشكلة رقم 1 في جميع أنحاء برنامجك. من الأفضل بكثير احتواؤه ضمن صنف واحد، خاصةً إذا كان بقية الكود يعتمد عليه.

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

## Solution

جميع تطبيقات Singleton لها هاتان الخطوتان المشتركتان:

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

إذا كان الكود لديك يملك وصولاً إلى صنف Singleton، فإنه يستطيع استدعاء الطريقة الساكنة لـ Singleton. لذا في كل مرة تُستدعى فيها تلك الطريقة، يُرجع دائماً نفس الكائن.

## Structure

1. يُعلن صنف **Singleton** عن الطريقة الساكنة `getInstance` التي تُرجع نفس نسخة الصنف.
يجب إخفاء مُنشئ Singleton عن كود العميل. يجب أن يكون استدعاء الطريقة `getInstance` هو الطريقة الوحيدة للحصول على كائن Singleton.

## Pseudocode

في هذا المثال، تعمل فئة اتصال قاعدة البيانات كـ **Singleton**. لا يمتلك هذا الصنف مُنشئاً عاماً، لذا الطريقة الوحيدة للحصول على كائنه هي استدعاء الطريقة `getInstance`. تُخزّن هذه الطريقة مؤقتاً أول كائن تم إنشاؤه وتُرجعه في جميع الاستدعاءات اللاحقة.

// يُعرّف صنف Database طريقة `getInstance` التي تتيح
// للعملاء الوصول إلى نفس نسخة اتصال قاعدة البيانات
// في جميع أنحاء البرنامج.
class Database is
    // يجب الإعلان عن الحقل المخصص لتخزين نسخة Singleton
    // كحقل ساكن.
    private static field instance: Database

    // يجب أن يكون مُنشئ Singleton خاصاً دائماً لمنع
    // استدعاءات الإنشاء المباشرة باستخدام المُشغّل `new`.
    private constructor Database() is
        // بعض كود التهيئة، مثل الاتصال الفعلي
        // بخادم قاعدة البيانات.
        // ...

    // الطريقة الساكنة التي تتحكم في الوصول إلى
    // نسخة Singleton.
    public static method getInstance() is
        if (Database.instance == null) then
            acquireThreadLock() and then
                // التحقق من أن النسخة لم تتم تهيئتها بعد
                // من قِبَل خيط آخر بينما كان هذا الخيط
                // ينتظر تحرير القفل.
                if (Database.instance == null) then
                    Database.instance = new Database()
        return Database.instance

    // أخيراً، يجب أن يُعرّف أي Singleton منطق أعمال
    // يمكن تنفيذه على نسخته.
    public method query(sql) is
        // على سبيل المثال، تمر جميع استعلامات قاعدة البيانات
        // لأي تطبيق عبر هذه الطريقة. لذلك يمكنك وضع
        // منطق التحكم في معدل الطلبات أو التخزين المؤقت هنا.
        // ...

class Application is
    method main() is
        Database foo = Database.getInstance()
        foo.query("SELECT ...")
        // ...
        Database bar = Database.getInstance()
        bar.query("SELECT ...")
        // سيحتوي المتغير `bar` على نفس الكائن
        // الموجود في المتغير `foo`.

## Applicability

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

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

 استخدم نمط Singleton عندما تحتاج إلى تحكم أكثر صرامة في المتغيرات العالمية.

 على عكس المتغيرات العالمية، يضمن نمط Singleton وجود نسخة واحدة فقط من الصنف. لا شيء، باستثناء صنف Singleton نفسه، يمكنه استبدال النسخة المخزنة مؤقتاً.

لاحظ أنه يمكنك دائماً تعديل هذا القيد والسماح بإنشاء أي عدد من نسخ Singleton. الكود الوحيد الذي يحتاج إلى تغيير هو جسم الطريقة `getInstance`.

## How to Implement

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

## Pros

* يمكنك التأكد من أن الصنف لديه نسخة واحدة فقط.
* تحصل على نقطة وصول عالمية لتلك النسخة.
* يتم تهيئة كائن Singleton فقط عند طلبه للمرة الأولى.

## Cons

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

## Relations with Other Patterns

* يمكن في الغالب تحويل صنف [Facade](/ar/design-patterns/facade) إلى [Singleton](/ar/design-patterns/singleton) إذ يكفي في معظم الحالات كائن facade واحد.
* يشبه [Flyweight](/ar/design-patterns/flyweight) نمط [Singleton](/ar/design-patterns/singleton) إذا تمكنت من اختزال جميع الحالات المشتركة للكائنات في كائن flyweight واحد. غير أن ثمة فرقين أساسيين بين هذين النمطين:

  1. يجب أن تكون هناك نسخة Singleton واحدة فقط، في حين يمكن أن يمتلك صنف _Flyweight_ نسخاً متعددة بحالات داخلية مختلفة.
  2. يمكن أن يكون كائن _Singleton_ قابلاً للتغيير. كائنات Flyweight غير قابلة للتغيير.
* يمكن تطبيق [Abstract Factories](/ar/design-patterns/abstract-factory) و[Builders](/ar/design-patterns/builder) و[Prototypes](/ar/design-patterns/prototype) جميعها كـ [Singletons](/ar/design-patterns/singleton).
## Relations

**Related patterns**

- [الواجهة (Facade)](/ar/design-patterns/facade.md)
- [وزن الذبابة](/ar/design-patterns/flyweight.md)
- [المصنع المجرد (Abstract Factory)](/ar/design-patterns/abstract-factory.md)
- [البنّاء](/ar/design-patterns/builder.md)
- [النموذج الأولي (Prototype)](/ar/design-patterns/prototype.md)

## Code Examples

### java

```java
package refactoring_guru.singleton.example.non_thread_safe;

public final class Singleton {
    private static Singleton instance;
    public String value;

    private Singleton(String value) {
        // الكود التالي يحاكي التهيئة البطيئة.
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        this.value = value;
    }

    public static Singleton getInstance(String value) {
        if (instance == null) {
            instance = new Singleton(value);
        }
        return instance;
    }
}

package refactoring_guru.singleton.example.non_thread_safe;

public class DemoSingleThread {
    public static void main(String[] args) {
        System.out.println("If you see the same value, then singleton was reused (yay!)" + "\n" +
                "If you see different values, then 2 singletons were created (booo!!)" + "\n\n" +
                "RESULT:" + "\n");
        Singleton singleton = Singleton.getInstance("FOO");
        Singleton anotherSingleton = Singleton.getInstance("BAR");
        System.out.println(singleton.value);
        System.out.println(anotherSingleton.value);
    }
}

If you see the same value, then singleton was reused (yay!)
If you see different values, then 2 singletons were created (booo!!)

RESULT:

FOO
FOO

package refactoring_guru.singleton.example.non_thread_safe;

public final class Singleton {
    private static Singleton instance;
    public String value;

    private Singleton(String value) {
        // الكود التالي يحاكي التهيئة البطيئة.
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        this.value = value;
    }

    public static Singleton getInstance(String value) {
        if (instance == null) {
            instance = new Singleton(value);
        }
        return instance;
    }
}

package refactoring_guru.singleton.example.non_thread_safe;

public class DemoMultiThread {
    public static void main(String[] args) {
        System.out.println("If you see the same value, then singleton was reused (yay!)" + "\n" +
                "If you see different values, then 2 singletons were created (booo!!)" + "\n\n" +
                "RESULT:" + "\n");
        Thread threadFoo = new Thread(new ThreadFoo());
        Thread threadBar = new Thread(new ThreadBar());
        threadFoo.start();
        threadBar.start();
    }

    static class ThreadFoo implements Runnable {
        @Override
        public void run() {
            Singleton singleton = Singleton.getInstance("FOO");
            System.out.println(singleton.value);
        }
    }

    static class ThreadBar implements Runnable {
        @Override
        public void run() {
            Singleton singleton = Singleton.getInstance("BAR");
            System.out.println(singleton.value);
        }
    }
}

If you see the same value, then singleton was reused (yay!)
If you see different values, then 2 singletons were created (booo!!)

RESULT:

FOO
BAR

package refactoring_guru.singleton.example.thread_safe;

public final class Singleton {
    // يجب إعلان الحقل volatile حتى يعمل قفل التحقق المزدوج
    // بشكل صحيح.
    private static volatile Singleton instance;

    public String value;

    private Singleton(String value) {
        this.value = value;
    }

    public static Singleton getInstance(String value) {
        // النهج المتبع هنا يُسمى القفل ذو التحقق المزدوج (DCL). وهو
        // موجود لمنع حالة التسابق بين خيوط متعددة قد
        // تحاول الحصول على نسخة Singleton في وقت واحد، مما يُنشئ
        // نسخاً منفصلة نتيجةً لذلك.
        //
        // قد يبدو أن وجود المتغير `result` هنا بلا فائدة
        // تماماً. غير أن هناك تحذيراً مهماً جداً عند
        // تنفيذ القفل ذي التحقق المزدوج في Java، ويُحل بواسطة
        // إدخال هذا المتغير المحلي.
        //
        // يمكنك قراءة المزيد حول مشكلات DCL في Java هنا:
        // https://refactoring.guru/java-dcl-issue
        Singleton result = instance;
        if (result != null) {
            return result;
        }
        synchronized(Singleton.class) {
            if (instance == null) {
                instance = new Singleton(value);
            }
            return instance;
        }
    }
}

package refactoring_guru.singleton.example.thread_safe;

public class DemoMultiThread {
    public static void main(String[] args) {
        System.out.println("If you see the same value, then singleton was reused (yay!)" + "\n" +
                "If you see different values, then 2 singletons were created (booo!!)" + "\n\n" +
                "RESULT:" + "\n");
        Thread threadFoo = new Thread(new ThreadFoo());
        Thread threadBar = new Thread(new ThreadBar());
        threadFoo.start();
        threadBar.start();
    }

    static class ThreadFoo implements Runnable {
        @Override
        public void run() {
            Singleton singleton = Singleton.getInstance("FOO");
            System.out.println(singleton.value);
        }
    }

    static class ThreadBar implements Runnable {
        @Override
        public void run() {
            Singleton singleton = Singleton.getInstance("BAR");
            System.out.println(singleton.value);
        }
    }
}

If you see the same value, then singleton was reused (yay!)
If you see different values, then 2 singletons were created (booo!!)

RESULT:

BAR
BAR
```

### csharp

```csharp
using System;

namespace RefactoringGuru.DesignPatterns.Singleton.Conceptual.NonThreadSafe
{
    // يعرّف صنف Singleton طريقة `GetInstance` التي تعمل بديلاً
    // عن المُنشئ وتتيح للعملاء الوصول إلى نفس النسخة من
    // هذا الصنف مراراً وتكراراً.

    // يجب أن يكون Singleton دائماً صنفاً 'sealed' لمنع وراثة الصنف
    // من خلال الأصناف الخارجية وكذلك الأصناف المتداخلة.
    public sealed class Singleton
    {
        // يجب أن يكون مُنشئ Singleton خاصاً دائماً لمنع
        // استدعاءات الإنشاء المباشرة باستخدام المُشغّل `new`.
        private Singleton() { }

        // تُخزَّن نسخة Singleton في حقل ساكن. توجد طرق متعددة
        // لتهيئة هذا الحقل، وكلها لها مزايا وعيوب متنوعة.
        // في هذا المثال سنعرض أبسط هذه الطرق،
        // والتي لا تعمل بشكل جيد في البرامج متعددة الخيوط.
        private static Singleton _instance;

        // هذه هي الطريقة الساكنة التي تتحكم في الوصول إلى نسخة
        // Singleton. في أول تشغيل، تُنشئ كائن Singleton وتضعه
        // في الحقل الساكن. في التشغيلات اللاحقة، تُرجع للعميل
        // الكائن الموجود المخزن في الحقل الساكن.
        public static Singleton GetInstance()
        {
            if (_instance == null)
            {
                _instance = new Singleton();
            }
            return _instance;
        }

        // أخيراً، يجب أن يُعرّف أي Singleton منطق أعمال يمكن
        // تنفيذه على نسخته.
        public void someBusinessLogic()
        {
            // ...
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // كود العميل.
            Singleton s1 = Singleton.GetInstance();
            Singleton s2 = Singleton.GetInstance();

            if (s1 == s2)
            {
                Console.WriteLine("Singleton works, both variables contain the same instance.");
            }
            else
            {
                Console.WriteLine("Singleton failed, variables contain different instances.");
            }
        }
    }
}

Singleton works, both variables contain the same instance.

using System;
using System.Threading;

namespace Singleton
{
    // يُسمى تطبيق Singleton هذا "قفل التحقق المزدوج". وهو آمن
    // في البيئة متعددة الخيوط ويوفر تهيئة كسولة لـ
    // كائن Singleton.
    class Singleton
    {
        private Singleton() { }

        private static Singleton _instance;

        // لدينا الآن كائن قفل سيُستخدم لمزامنة الخيوط
        // أثناء أول وصول إلى Singleton.
        private static readonly object _lock = new object();

        public static Singleton GetInstance(string value)
        {
            // هذا الشرط ضروري لمنع الخيوط من التعثر على
            // القفل بمجرد أن تكون النسخة جاهزة.
            if (_instance == null)
            {
                // الآن، تخيل أن البرنامج قد تم تشغيله للتو. نظراً
                // لعدم وجود نسخة Singleton بعد، يمكن لخيوط متعددة
                // تجاوز الشرط السابق والوصول إلى هذه النقطة
                // في نفس الوقت تقريباً. سيحصل أولها على
                // القفل وسيمضي قُدُماً، بينما ستنتظر البقية هنا.
                lock (_lock)
                {
                    // الخيط الأول الذي يحصل على القفل يصل إلى هذا
                    // الشرط، يدخل ويُنشئ نسخة Singleton. بمجرد
                    // خروجه من كتلة القفل، قد يدخل الخيط الذي
                    // كان ينتظر تحرير القفل إلى هذا القسم.
                    // لكن نظراً لأن حقل Singleton تمت تهيئته
                    // مسبقاً، لن ينشئ الخيط كائناً جديداً.
                    if (_instance == null)
                    {
                        _instance = new Singleton();
                        _instance.Value = value;
                    }
                }
            }
            return _instance;
        }

        // سنستخدم هذه الخاصية لإثبات أن Singleton يعمل فعلاً.
        public string Value { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // كود العميل.
            
            Console.WriteLine(
                "{0}\n{1}\n\n{2}\n",
                "If you see the same value, then singleton was reused (yay!)",
                "If you see different values, then 2 singletons were created (booo!!)",
                "RESULT:"
            );
            
            Thread process1 = new Thread(() =>
            {
                TestSingleton("FOO");
            });
            Thread process2 = new Thread(() =>
            {
                TestSingleton("BAR");
            });
            
            process1.Start();
            process2.Start();
            
            process1.Join();
            process2.Join();
        }
        
        public static void TestSingleton(string value)
        {
            Singleton singleton = Singleton.GetInstance(value);
            Console.WriteLine(singleton.Value);
        } 
    }
}

FOO
FOO
```

### cpp

```cpp
/**
 * يعرّف صنف Singleton طريقة `GetInstance` التي تعمل بديلاً
 * عن المُنشئ وتتيح للعملاء الوصول إلى نفس النسخة من
 * هذا الصنف مراراً وتكراراً.
 */
class Singleton
{

    /**
     * يجب أن يكون مُنشئ Singleton خاصاً دائماً لمنع
     * استدعاءات الإنشاء المباشرة باستخدام المُشغّل `new`.
     */

protected:
    Singleton(const std::string value): value_(value)
    {
    }

    static Singleton* singleton_;

    std::string value_;

public:

    /**
     * يجب ألا تكون Singletons قابلة للاستنساخ.
     */
    Singleton(Singleton &other) = delete;
    /**
     * يجب ألا تكون Singletons قابلة للإسناد.
     */
    void operator=(const Singleton &) = delete;
    /**
     * هذه هي الطريقة الساكنة التي تتحكم في الوصول إلى
     * نسخة Singleton. في أول تشغيل، تُنشئ كائن Singleton وتضعه
     * في الحقل الساكن. في التشغيلات اللاحقة، تُرجع للعميل
     * الكائن الموجود المخزن في الحقل الساكن.
     */

    static Singleton *GetInstance(const std::string& value);
    /**
     * أخيراً، يجب أن يُعرّف أي Singleton منطق أعمال يمكن
     * تنفيذه على نسخته.
     */
    void SomeBusinessLogic()
    {
        // ...
    }

    std::string value() const{
        return value_;
    } 
};

Singleton* Singleton::singleton_= nullptr;;

/**
 * يجب تعريف الطرق الساكنة خارج الصنف.
 */
Singleton *Singleton::GetInstance(const std::string& value)
{
    /**
     * This is a safer way to create an instance. instance = new Singleton is
     * dangeruous in case two instance threads wants to access at the same time
     */
    if(singleton_==nullptr){
        singleton_ = new Singleton(value);
    }
    return singleton_;
}

void ThreadFoo(){
    // الكود التالي يحاكي التهيئة البطيئة.
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    Singleton* singleton = Singleton::GetInstance("FOO");
    std::cout << singleton->value() << "\n";
}

void ThreadBar(){
    // الكود التالي يحاكي التهيئة البطيئة.
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    Singleton* singleton = Singleton::GetInstance("BAR");
    std::cout << singleton->value() << "\n";
}


int main()
{
    std::cout <<"If you see the same value, then singleton was reused (yay!\n" <<
                "If you see different values, then 2 singletons were created (booo!!)\n\n" <<
                "RESULT:\n";   
    std::thread t1(ThreadFoo);
    std::thread t2(ThreadBar);
    t1.join();
    t2.join();

    return 0;
}

If you see the same value, then singleton was reused (yay!
If you see different values, then 2 singletons were created (booo!!)

RESULT:
BAR
FOO

/**
 * يعرّف صنف Singleton طريقة `GetInstance` التي تعمل بديلاً
 * عن المُنشئ وتتيح للعملاء الوصول إلى نفس النسخة من
 * هذا الصنف مراراً وتكراراً.
 */
class Singleton
{

    /**
     * يجب أن يكون مُنشئ/مُتلف Singleton خاصاً دائماً لمنع
     * استدعاءات الإنشاء/التدمير المباشرة باستخدام المُشغّل `new`/`delete`.
     */
private:
    static Singleton * pinstance_;
    static std::mutex mutex_;

protected:
    Singleton(const std::string value): value_(value)
    {
    }
    ~Singleton() {}
    std::string value_;

public:
    /**
     * يجب ألا تكون Singletons قابلة للاستنساخ.
     */
    Singleton(Singleton &other) = delete;
    /**
     * يجب ألا تكون Singletons قابلة للإسناد.
     */
    void operator=(const Singleton &) = delete;
    /**
     * هذه هي الطريقة الساكنة التي تتحكم في الوصول إلى
     * نسخة Singleton. في أول تشغيل، تُنشئ كائن Singleton وتضعه
     * في الحقل الساكن. في التشغيلات اللاحقة، تُرجع للعميل
     * الكائن الموجود المخزن في الحقل الساكن.
     */

    static Singleton *GetInstance(const std::string& value);
    /**
     * أخيراً، يجب أن يُعرّف أي Singleton منطق أعمال يمكن
     * تنفيذه على نسخته.
     */
    void SomeBusinessLogic()
    {
        // ...
    }
    
    std::string value() const{
        return value_;
    } 
};

/**
 * يجب تعريف الطرق الساكنة خارج الصنف.
 */

Singleton* Singleton::pinstance_{nullptr};
std::mutex Singleton::mutex_;

/**
 * في أول مرة نستدعي فيها GetInstance سنقفل موقع التخزين
 *      ثم نتأكد مرة أخرى أن المتغير null ثم
 *      نضبط القيمة.
 */
Singleton *Singleton::GetInstance(const std::string& value)
{
    std::lock_guard<std::mutex> lock(mutex_);
    if (pinstance_ == nullptr)
    {
        pinstance_ = new Singleton(value);
    }
    return pinstance_;
}

void ThreadFoo(){
    // الكود التالي يحاكي التهيئة البطيئة.
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    Singleton* singleton = Singleton::GetInstance("FOO");
    std::cout << singleton->value() << "\n";
}

void ThreadBar(){
    // الكود التالي يحاكي التهيئة البطيئة.
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    Singleton* singleton = Singleton::GetInstance("BAR");
    std::cout << singleton->value() << "\n";
}

int main()
{   
    std::cout <<"If you see the same value, then singleton was reused (yay!\n" <<
                "If you see different values, then 2 singletons were created (booo!!)\n\n" <<
                "RESULT:\n";   
    std::thread t1(ThreadFoo);
    std::thread t2(ThreadBar);
    t1.join();
    t2.join();
    
    return 0;
}

If you see the same value, then singleton was reused (yay!
If you see different values, then 2 singletons were created (booo!!)

RESULT:
FOO
FOO
```

### go

```go
package main

import (
	"fmt"
	"sync"
)

var lock = &sync.Mutex{}

type single struct {
}

var singleInstance *single

func getInstance() *single {
	if singleInstance == nil {
		lock.Lock()
		defer lock.Unlock()
		if singleInstance == nil {
			fmt.Println("Creating single instance now.")
			singleInstance = &single{}
		} else {
			fmt.Println("Single instance already created.")
		}
	} else {
		fmt.Println("Single instance already created.")
	}

	return singleInstance
}

package main

import (
	"fmt"
)

func main() {

	for i := 0; i < 30; i++ {
		go getInstance()
	}

	// تُشبه Scanln دالةَ Scan، لكنها تتوقف عن المسح عند سطر جديد
	// ويجب أن يكون بعد العنصر الأخير سطر جديد أو EOF.
	fmt.Scanln()
}

Creating single instance now.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.
Single instance already created.

package main

import (
	"fmt"
	"sync"
)

var once sync.Once

type single struct {
}

var singleInstance *single

func getInstance() *single {
	if singleInstance == nil {
		once.Do(
			func() {
				fmt.Println("Creating single instance now.")
				singleInstance = &single{}
			})
	} else {
		fmt.Println("Single instance already created.")
	}

	return singleInstance
}

package main

import (
	"fmt"
)

func main() {

	for i := 0; i < 30; i++ {
		go getInstance()
	}

	// تُشبه Scanln دالةَ Scan، لكنها تتوقف عن المسح عند سطر جديد
	// ويجب أن يكون بعد العنصر الأخير سطر جديد أو EOF.
	fmt.Scanln()
}

Creating single instance now.
Single instance already created.
Single instance already created.
```

### php

```php
<?php

namespace RefactoringGuru\Singleton\Conceptual;

/**
 * يعرّف صنف Singleton طريقة `GetInstance` التي تعمل بديلاً
 * عن المُنشئ وتتيح للعملاء الوصول إلى نفس النسخة من
 * هذا الصنف مراراً وتكراراً.
 */
class Singleton
{
    /**
     * تُخزَّن نسخة Singleton في حقل ساكن. هذا الحقل عبارة عن
     * مصفوفة، لأننا سنسمح لـ Singleton بامتلاك أصناف فرعية. كل عنصر
     * في هذه المصفوفة سيكون نسخة من صنف Singleton فرعي محدد.
     * ستعرف كيف يعمل هذا بعد لحظة.
     */
    private static $instances = [];

    /**
     * يجب أن يكون مُنشئ Singleton خاصاً دائماً لمنع
     * استدعاءات الإنشاء المباشرة باستخدام المُشغّل `new`.
     */
    protected function __construct()
    {
    }

    /**
     * يجب ألا تكون Singletons قابلة للاستنساخ.
     */
    protected function __clone()
    {
    }

    /**
     * يجب ألا تكون Singletons قابلة للاستعادة من السلاسل النصية.
     */
    public function __wakeup()
    {
        throw new \Exception("Cannot unserialize a singleton.");
    }

    /**
     * هذه هي الطريقة الساكنة التي تتحكم في الوصول إلى
     * نسخة Singleton. في أول تشغيل، تُنشئ كائن Singleton وتضعه
     * في الحقل الساكن. في التشغيلات اللاحقة، تُرجع للعميل
     * الكائن الموجود المخزن في الحقل الساكن.
     *
     * يتيح هذا التطبيق استيراث صنف Singleton مع الإبقاء على
     * نسخة واحدة فقط من كل صنف فرعي.
     */
    public static function getInstance(): Singleton
    {
        $cls = static::class;
        if (!isset(self::$instances[$cls])) {
            self::$instances[$cls] = new static();
        }

        return self::$instances[$cls];
    }

    /**
     * أخيراً، يجب أن يُعرّف أي Singleton منطق أعمال يمكن
     * تنفيذه على نسخته.
     */
    public function someBusinessLogic()
    {
        // ...
    }
}

/**
 * كود العميل.
 */
function clientCode()
{
    $s1 = Singleton::getInstance();
    $s2 = Singleton::getInstance();
    if ($s1 === $s2) {
        echo "Singleton works, both variables contain the same instance.";
    } else {
        echo "Singleton failed, variables contain different instances.";
    }
}

clientCode();

Singleton works, both variables contain the same instance.

<?php

namespace RefactoringGuru\Singleton\RealWorld;

/**
 * إذا كنت بحاجة إلى دعم عدة أنواع من Singletons في تطبيقك، يمكنك
 * تعريف الميزات الأساسية لـ Singleton في صنف أساسي، مع نقل
 * منطق الأعمال الفعلي (مثل التسجيل) إلى الأصناف الفرعية.
 */
class Singleton
{
    /**
     * تقطن نسخة Singleton الفعلية دائماً تقريباً داخل حقل ساكن.
     * في هذه الحالة، الحقل الساكن عبارة عن مصفوفة تخزن فيها
     * كل أصناف Singleton الفرعية نسختها الخاصة.
     */
    private static $instances = [];

    /**
     * لا يجب أن يكون مُنشئ Singleton عاماً. غير أنه لا يمكن أن
     * يكون خاصاً أيضاً إذا أردنا السماح بالاستيراث.
     */
    protected function __construct()
    {
    }

    /**
     * الاستنساخ وإلغاء التسلسل غير مسموح بهما لـ Singletons.
     */
    protected function __clone()
    {
    }

    public function __wakeup()
    {
        throw new \Exception("Cannot unserialize singleton");
    }

    /**
     * الطريقة التي تستخدمها للحصول على نسخة Singleton.
     */
    public static function getInstance()
    {
        $subclass = static::class;
        if (!isset(self::$instances[$subclass])) {
            // لاحظ أننا هنا نستخدم الكلمة المفتاحية "static" بدلاً من
            // اسم الصنف الفعلي. في هذا السياق، "static" تعني "اسم
            // الصنف الحالي". هذه التفصيلة مهمة لأنه عند استدعاء
            // الطريقة على الصنف الفرعي، نريد إنشاء نسخة من ذلك
            // الصنف الفرعي هنا.

            self::$instances[$subclass] = new static();
        }
        return self::$instances[$subclass];
    }
}

/**
 * صنف التسجيل هو الاستخدام الأشهر والأكثر إشادةً لنمط Singleton.
 * في معظم الحالات، تحتاج إلى كائن تسجيل واحد يكتب في ملف سجل
 * واحد (تحكم في مورد مشترك). كما تحتاج إلى طريقة ملائمة للوصول
 * إلى تلك النسخة من أي سياق في تطبيقك (نقطة وصول عالمية).
 */
class Logger extends Singleton
{
    /**
     * مورد مؤشر الملف لملف السجل.
     */
    private $fileHandle;

    /**
     * نظراً لاستدعاء مُنشئ Singleton مرة واحدة فقط، يُفتح مورد
     * ملف واحد فقط في جميع الأوقات.
     *
     * لاحظ أننا، للتبسيط، نفتح دفق وحدة التحكم بدلاً
     * من الملف الفعلي هنا.
     */
    protected function __construct()
    {
        $this->fileHandle = fopen('php://stdout', 'w');
    }

    /**
     * كتابة إدخال سجل في مورد الملف المفتوح.
     */
    public function writeLog(string $message): void
    {
        $date = date('Y-m-d');
        fwrite($this->fileHandle, "$date: $message\n");
    }

    /**
     * اختصار مفيد لتقليل كمية الكود اللازمة لتسجيل الرسائل
     * من كود العميل.
     */
    public static function log(string $message): void
    {
        $logger = static::getInstance();
        $logger->writeLog($message);
    }
}

/**
 * تطبيق نمط Singleton على تخزين الإعدادات هو أيضاً ممارسة شائعة.
 * غالباً ما تحتاج إلى الوصول إلى إعدادات التطبيق من أماكن مختلفة
 * كثيرة في البرنامج. يمنحك Singleton هذا الراحة.
 */
class Config extends Singleton
{
    private $hashmap = [];

    public function getValue(string $key): string
    {
        return $this->hashmap[$key];
    }

    public function setValue(string $key, string $value): void
    {
        $this->hashmap[$key] = $value;
    }
}

/**
 * كود العميل.
 */
Logger::log("Started!");

// مقارنة قيم singleton للمُسجِّل.
$l1 = Logger::getInstance();
$l2 = Logger::getInstance();
if ($l1 === $l2) {
    Logger::log("Logger has a single instance.");
} else {
    Logger::log("Loggers are different.");
}

// التحقق من كيفية حفظ Config singleton للبيانات...
$config1 = Config::getInstance();
$login = "test_login";
$password = "test_password";
$config1->setValue("login", $login);
$config1->setValue("password", $password);
// ...واستعادتها.
$config2 = Config::getInstance();
if (
    $login == $config2->getValue("login") &&
    $password == $config2->getValue("password")
) {
    Logger::log("Config singleton also works fine.");
}

Logger::log("Finished!");

2018-06-04: Started!
2018-06-04: Logger has a single instance.
2018-06-04: Config singleton also works fine.
2018-06-04: Finished!
```

### python

```python
class SingletonMeta(type):
    """
    يمكن تطبيق صنف Singleton بطرق مختلفة في Python. تشمل بعض
    الطرق المحتملة: الصنف الأساسي، والمُزخرف، والميتاكلاس.
    سنستخدم الميتاكلاس لأنه الأنسب لهذا الغرض.
    """

    _instances = {}

    def __call__(cls, *args, **kwargs):
        """
        التغييرات المحتملة على قيمة وسيط `__init__` لا تؤثر
        على النسخة المُرجَعة.
        """
        if cls not in cls._instances:
            instance = super().__call__(*args, **kwargs)
            cls._instances[cls] = instance
        return cls._instances[cls]


class Singleton(metaclass=SingletonMeta):
    def some_business_logic(self):
        """
        أخيراً، يجب أن يُعرّف أي Singleton منطق أعمال يمكن
        تنفيذه على نسخته.
        """

        # ...


if __name__ == "__main__":
    # كود العميل.

    s1 = Singleton()
    s2 = Singleton()

    if id(s1) == id(s2):
        print("Singleton works, both variables contain the same instance.")
    else:
        print("Singleton failed, variables contain different instances.")

Singleton works, both variables contain the same instance.

from threading import Lock, Thread


class SingletonMeta(type):
    """
    هذا تطبيق Singleton آمن للتعامل مع الخيوط المتعددة.
    """

    _instances = {}

    _lock: Lock = Lock()
    """
    لدينا الآن كائن قفل سيُستخدم لمزامنة الخيوط أثناء
    أول وصول إلى Singleton.
    """

    def __call__(cls, *args, **kwargs):
        """
        التغييرات المحتملة على قيمة وسيط `__init__` لا تؤثر
        على النسخة المُرجَعة.
        """
        # الآن، تخيل أن البرنامج قد تم تشغيله للتو. نظراً لعدم وجود
        # نسخة Singleton بعد، يمكن لخيوط متعددة تجاوز الشرط السابق
        # والوصول إلى هذه النقطة في نفس الوقت تقريباً. سيحصل
        # أولها على القفل وسيمضي قُدُماً، بينما ستنتظر البقية هنا.
        with cls._lock:
            # الخيط الأول الذي يحصل على القفل يصل إلى هذا الشرط،
            # يدخل ويُنشئ نسخة Singleton. بمجرد خروجه من كتلة القفل،
            # قد يدخل الخيط الذي كان ينتظر تحرير القفل إلى هذا
            # القسم. لكن نظراً لأن حقل Singleton تمت تهيئته مسبقاً،
            # لن ينشئ الخيط كائناً جديداً.
            if cls not in cls._instances:
                instance = super().__call__(*args, **kwargs)
                cls._instances[cls] = instance
        return cls._instances[cls]


class Singleton(metaclass=SingletonMeta):
    value: str = None
    """
    سنستخدم هذه الخاصية لإثبات أن Singleton يعمل فعلاً.
    """

    def __init__(self, value: str) -> None:
        self.value = value

    def some_business_logic(self):
        """
        أخيراً، يجب أن يُعرّف أي Singleton منطق أعمال يمكن
        تنفيذه على نسخته.
        """


def test_singleton(value: str) -> None:
    singleton = Singleton(value)
    print(singleton.value)


if __name__ == "__main__":
    # كود العميل.

    print("If you see the same value, then singleton was reused (yay!)\n"
          "If you see different values, "
          "then 2 singletons were created (booo!!)\n\n"
          "RESULT:\n")

    process1 = Thread(target=test_singleton, args=("FOO",))
    process2 = Thread(target=test_singleton, args=("BAR",))
    process1.start()
    process2.start()

If you see the same value, then singleton was reused (yay!)
If you see different values, then 2 singletons were created (booo!!)

RESULT:

FOO
FOO
```

### ruby

```ruby
# يعرّف صنف Singleton طريقة `instance` التي تتيح للعملاء الوصول إلى
# نسخة Singleton الفريدة.
class Singleton
  @instance = new

  private_class_method :new

  # الطريقة الساكنة التي تتحكم في الوصول إلى نسخة Singleton.
  #
  # يتيح هذا التطبيق استيراث صنف Singleton مع الإبقاء على
  # نسخة واحدة فقط من كل صنف فرعي.
  def self.instance
    @instance
  end

  # أخيراً، يجب أن يُعرّف أي Singleton منطق أعمال يمكن
  # تنفيذه على نسخته.
  def some_business_logic
    # ...
  end
end

# كود العميل.

s1 = Singleton.instance
s2 = Singleton.instance

if s1.equal?(s2)
  print 'Singleton works, both variables contain the same instance.'
else
  print 'Singleton failed, variables contain different instances.'
end

Singleton works, both variables contain the same instance.

# يعرّف صنف Singleton طريقة `instance` التي تتيح للعملاء الوصول إلى
# نسخة Singleton الفريدة.
class Singleton
  attr_reader :value

  @instance_mutex = Mutex.new

  private_class_method :new

  def initialize(value)
    @value = value
  end

  # الطريقة الساكنة التي تتحكم في الوصول إلى نسخة Singleton.
  #
  # يتيح هذا التطبيق استيراث صنف Singleton مع الإبقاء على
  # نسخة واحدة فقط من كل صنف فرعي.
  def self.instance(value)
    return @instance if @instance

    @instance_mutex.synchronize do
      @instance ||= new(value)
    end

    @instance
  end

  # أخيراً، يجب أن يُعرّف أي Singleton منطق أعمال يمكن
  # تنفيذه على نسخته.
  def some_business_logic
    # ...
  end
end

# @param [String] value
def test_singleton(value)
  singleton = Singleton.instance(value)
  puts singleton.value
end

# كود العميل.

puts "If you see the same value, then singleton was reused (yay!)\n"\
     "If you see different values, then 2 singletons were created (booo!!)\n\n"\
     "RESULT:\n\n"

process1 = Thread.new { test_singleton('FOO') }
process2 = Thread.new { test_singleton('BAR') }
process1.join
process2.join

If you see the same value, then singleton was reused (yay!)
If you see different values, then 2 singletons were created (booo!!)

RESULT:

FOO
FOO
```

### rust

```rust
//! الطريقة الآمنة البحتة لتطبيق Singleton في Rust هي عدم استخدام متغيرات ساكنة
//! وتمرير كل شيء عبر وسيطات الدوال.
//! أقدم متغير حي هو كائن يُنشأ عند بداية `main()`.

fn change(global_state: &mut u32) {
    *global_state += 1;
}

fn main() {
    let mut global_state = 0u32;

    change(&mut global_state);

    println!("Final state: {}", global_state);
}

Final state: 1

//! مأخوذ من: https://stackoverflow.com/questions/27791532/how-do-i-create-a-global-mutable-singleton
//!
//! لا تسمح Rust فعلياً بنمط Singleton دون `unsafe` لأنها
//! لا تمتلك حالة عالمية قابلة للتغيير بأمان.
//!
//! تتيح `lazy-static` الإعلان عن متغير ساكن مع تهيئة كسولة
//! عند أول وصول. يتم تطبيقها فعلياً عبر `unsafe` مع التعامل مع `static mut`،
//! لكنها تُبقي الكود خالياً من كتل `unsafe`.
//!
//! توفر `Mutex` وصولاً آمناً إلى كائن واحد.

use lazy_static::lazy_static;
use std::sync::Mutex;

lazy_static! {
    static ref ARRAY: Mutex<Vec<u8>> = Mutex::new(vec![]);
}

fn do_a_call() {
    ARRAY.lock().unwrap().push(1);
}

fn main() {
    do_a_call();
    do_a_call();
    do_a_call();

    println!("Called {}", ARRAY.lock().unwrap().len());
}

Called 3

//! ructc 1.63
//! https://stackoverflow.com/questions/27791532/how-do-i-create-a-global-mutable-singleton
//!
//! ابتداءً من Rust 1.63، أصبح العمل مع singletons عالمية قابلة للتغيير أسهل،
//! رغم أنه لا يزال من الأفضل تجنب المتغيرات العالمية في معظم
//! الحالات.
//!
//! بما أن `Mutex::new` أصبحت `const`، يمكنك استخدام أقفال `Mutex` ساكنة عالمية
//! دون الحاجة إلى تهيئة كسولة.

use std::sync::Mutex;

static ARRAY: Mutex<Vec<i32>> = Mutex::new(Vec::new());

fn do_a_call() {
    ARRAY.lock().unwrap().push(1);
}

fn main() {
    do_a_call();
    do_a_call();
    do_a_call();

    let array = ARRAY.lock().unwrap();
    println!("Called {} times: {:?}", array.len(), array);
    drop(array);

    *ARRAY.lock().unwrap() = vec![3, 4, 5];

    println!("New singleton object: {:?}", ARRAY.lock().unwrap());
}

Called 3 times
```

### swift

```swift
import XCTest

/// يعرّف صنف Singleton الحقل `shared` الذي يتيح للعملاء الوصول إلى
/// نسخة Singleton الفريدة.
class Singleton {

    /// الحقل الساكن الذي يتحكم في الوصول إلى نسخة Singleton.
    ///
    /// يتيح هذا التطبيق توسيع صنف Singleton مع الإبقاء على
    /// نسخة واحدة فقط من كل صنف فرعي.
    static var shared: Singleton = {
        let instance = Singleton()
        // ... ضبط إعدادات النسخة
        // ...
        return instance
    }()

    /// يجب أن يكون مُهيِّئ Singleton خاصاً دائماً لمنع
    /// استدعاءات الإنشاء المباشرة باستخدام المُشغّل `new`.
    private init() {}

    /// أخيراً، يجب أن يُعرّف أي Singleton منطق أعمال يمكن
    /// تنفيذه على نسخته.
    func someBusinessLogic() -> String {
        // ...
        return "Result of the 'someBusinessLogic' call"
    }
}

/// يجب ألا تكون Singletons قابلة للاستنساخ.
extension Singleton: NSCopying {

    func copy(with zone: NSZone? = nil) -> Any {
        return self
    }
}

/// كود العميل.
class Client {
    // ...
    static func someClientCode() {
        let instance1 = Singleton.shared
        let instance2 = Singleton.shared

        if (instance1 === instance2) {
            print("Singleton works, both variables contain the same instance.")
        } else {
            print("Singleton failed, variables contain different instances.")
        }
    }
    // ...
}

/// Let's see how it all works together.
class SingletonConceptual: XCTestCase {

    func testSingletonConceptual() {
        Client.someClientCode()
    }
}

Singleton works, both variables contain the same instance.

import XCTest

/// نمط تصميم Singleton
///
/// الهدف: ضمان أن الصنف لديه نسخة واحدة، وتوفير نقطة وصول
/// عالمية إليها.

class SingletonRealWorld: XCTestCase {

    func testSingletonRealWorld() {

        /// يوجد عرضان للتحكم.
        ///
        /// تعرض MessagesListVC قائمة بآخر الرسائل من محادثات المستخدم.
        /// تعرض ChatVC محادثة مع صديق.
        ///
        /// تجلب FriendsChatService الرسائل من خادم وتزود جميع
        /// المشتركين (وحدات التحكم في المثال) بالرسائل الجديدة والمحذوفة.
        ///
        /// تُستخدم FriendsChatService من كلا وحدتَي التحكم. يمكن
        /// تطبيقها كنسخة من صنف أو كمتغير عالمي.
        ///
        /// في هذا المثال، من المهم امتلاك نسخة واحدة فقط تقوم
        /// بالعمل كثيف الموارد.

        let listVC = MessagesListVC()
        let chatVC = ChatVC()

        listVC.startReceiveMessages()
        chatVC.startReceiveMessages()

        /// ... إضافة وحدات التحكم إلى مكدس التنقل ...
    }
}


class BaseVC: UIViewController, MessageSubscriber {

    func accept(new messages: [Message]) {
        /// معالجة الرسائل الجديدة في الصنف الأساسي
    }

    func accept(removed messages: [Message]) {
        /// معالجة الرسائل المحذوفة في الصنف الأساسي
    }

    func startReceiveMessages() {

        /// يمكن حقن Singleton كتبعية. غير أنه من منظور توضيحي،
        /// يستدعي هذا المثال FriendsChatService مباشرة لتوضيح
        /// هدف النمط، وهو: "...توفير نقطة الوصول العالمية إلى النسخة..."

        FriendsChatService.shared.add(subscriber: self)
    }
}

class MessagesListVC: BaseVC {

    override func accept(new messages: [Message]) {
        print("MessagesListVC accepted 'new messages'")
        /// معالجة الرسائل الجديدة في الصنف الفرعي
    }

    override func accept(removed messages: [Message]) {
        print("MessagesListVC accepted 'removed messages'")
        /// معالجة الرسائل المحذوفة في الصنف الفرعي
    }

    override func startReceiveMessages() {
        print("MessagesListVC starts receive messages")
        super.startReceiveMessages()
    }
}

class ChatVC: BaseVC {

    override func accept(new messages: [Message]) {
        print("ChatVC accepted 'new messages'")
        /// معالجة الرسائل الجديدة في الصنف الفرعي
    }

    override func accept(removed messages: [Message]) {
        print("ChatVC accepted 'removed messages'")
        /// معالجة الرسائل المحذوفة في الصنف الفرعي
    }

    override func startReceiveMessages() {
        print("ChatVC starts receive messages")
        super.startReceiveMessages()
    }
}

/// بروتوكول لأحداث الاستدعاء

protocol MessageSubscriber {

    func accept(new messages: [Message])
    func accept(removed messages: [Message])
}

/// بروتوكول للتواصل مع خدمة الرسائل

protocol MessageService {

    func add(subscriber: MessageSubscriber)
}

/// نموذج نطاق الرسالة

struct Message {

    let id: Int
    let text: String
}


class FriendsChatService: MessageService {

    static let shared = FriendsChatService()

    private var subscribers = [MessageSubscriber]()

    func add(subscriber: MessageSubscriber) {

        /// في هذا المثال، يبدأ الجلب مجدداً عند إضافة مشترك جديد
        subscribers.append(subscriber)

        /// لاحظ أن المشترك الأول سيتلقى الرسائل مجدداً عند
        /// إضافة المشترك الثاني
        startFetching()
    }

    func startFetching() {

        /// إعداد مكدس الشبكة، وإنشاء اتصال...
        /// ...واسترداد البيانات من خادم

        let newMessages = [Message(id: 0, text: "Text0"),
                           Message(id: 5, text: "Text5"),
                           Message(id: 10, text: "Text10")]

        let removedMessages = [Message(id: 1, text: "Text0")]

        /// إرسال البيانات المحدَّثة إلى المشتركين
        receivedNew(messages: newMessages)
        receivedRemoved(messages: removedMessages)
    }
}

private extension FriendsChatService {

    func receivedNew(messages: [Message]) {

        subscribers.forEach { item in
            item.accept(new: messages)
        }
    }

    func receivedRemoved(messages: [Message]) {

        subscribers.forEach { item in
            item.accept(removed: messages)
        }
    }
}

MessagesListVC starts receive messages
MessagesListVC accepted 'new messages'
MessagesListVC accepted 'removed messages'
======== At this point, the second subscriber is added ======
ChatVC starts receive messages
MessagesListVC accepted 'new messages'
ChatVC accepted 'new messages'
MessagesListVC accepted 'removed messages'
ChatVC accepted 'removed messages'
```

### typescript

```typescript
/**
 * يعرّف صنف Singleton أداة getter للـ `instance`، تتيح للعملاء
 * الوصول إلى نسخة Singleton الفريدة.
 */
class Singleton {
    static #instance: Singleton;

    /**
     * يجب أن يكون مُنشئ Singleton خاصاً دائماً لمنع
     * استدعاءات الإنشاء المباشرة باستخدام المُشغّل `new`.
     */
    private constructor() { }

    /**
     * أداة getter الساكنة التي تتحكم في الوصول إلى نسخة Singleton.
     *
     * يتيح هذا التطبيق توسيع صنف Singleton مع الإبقاء على
     * نسخة واحدة فقط من كل صنف فرعي.
     */
    public static get instance(): Singleton {
        if (!Singleton.#instance) {
            Singleton.#instance = new Singleton();
        }

        return Singleton.#instance;
    }

    /**
     * أخيراً، يمكن لأي Singleton تعريف منطق أعمال يمكن
     * تنفيذه على نسخته.
     */
    public someBusinessLogic() {
        // ...
    }
}

/**
 * كود العميل.
 */
function clientCode() {
    const s1 = Singleton.instance;
    const s2 = Singleton.instance;

    if (s1 === s2) {
        console.log(
            'Singleton works, both variables contain the same instance.'
        );
    } else {
        console.log('Singleton failed, variables contain different instances.');
    }
}

clientCode();

Singleton works, both variables contain the same instance.
```

