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

> الواجهة (Facade) هي نمط تصميم هيكلي يوفر واجهة مبسطة لمكتبة أو إطار عمل أو أي مجموعة معقدة أخرى من الفئات.

## Intent

**الواجهة (Facade)** هي نمط تصميم هيكلي يوفر واجهة مبسطة لمكتبة أو إطار عمل أو أي مجموعة معقدة أخرى من الفئات.

## Problem

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

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

## Solution

الواجهة هي فئة توفر واجهة بسيطة لنظام فرعي معقد يحتوي على الكثير من الأجزاء المتحركة. قد توفر الواجهة وظائف محدودة مقارنةً بالتعامل مع النظام الفرعي مباشرة. غير أنها تتضمن فقط تلك الميزات التي يهتم بها العملاء فعلاً.

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

على سبيل المثال، قد يستخدم تطبيق يرفع مقاطع فيديو قصيرة ومضحكة عن القطط إلى منصات التواصل الاجتماعي مكتبة تحويل فيديو احترافية. غير أن كل ما يحتاجه هو فئة تحتوي على الأسلوب الواحد `encode(filename, format)`. بعد إنشاء هذه الفئة وربطها بمكتبة تحويل الفيديو، ستحصل على أولى واجهاتك.

## Structure

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

## Pseudocode

في هذا المثال، يبسّط نمط **الواجهة (Facade)** التفاعل مع إطار عمل تحويل الفيديو المعقد.

مثال على عزل تبعيات متعددة داخل فئة واجهة واحدة.

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

// هذه بعض فئات إطار عمل تحويل الفيديو المعقد التابع لطرف ثالث.
// لا نتحكم في هذا الكود، وبالتالي لا يمكننا تبسيطه.

class VideoFile
// ...

class OggCompressionCodec
// ...

class MPEG4CompressionCodec
// ...

class CodecFactory
// ...

class BitrateReader
// ...

class AudioMixer
// ...

// ننشئ فئة واجهة لإخفاء تعقيد إطار العمل
// خلف واجهة بسيطة. وهو مقايضة بين الوظائف والبساطة.
class VideoConverter is
    method convert(filename, format):File is
        file = new VideoFile(filename)
        sourceCodec = (new CodecFactory).extract(file)
        if (format == "mp4")
            destinationCodec = new MPEG4CompressionCodec()
        else
            destinationCodec = new OggCompressionCodec()
        buffer = BitrateReader.read(filename, sourceCodec)
        result = BitrateReader.convert(buffer, destinationCodec)
        result = (new AudioMixer()).fix(result)
        return new File(result)

// فئات التطبيق لا تعتمد على الكثير من الفئات
// التي يوفرها إطار العمل المعقد. كذلك، إذا قررت
// التبديل إلى إطار عمل آخر، فأنت بحاجة فقط إلى إعادة كتابة فئة الواجهة.
class Application is
    method main() is
        convertor = new VideoConverter()
        mp4 = convertor.convert("funny-cats-video.ogg", "mp4")
        mp4.save()

## Applicability

استخدم نمط الواجهة (Facade) عندما تحتاج إلى واجهة محدودة لكنها مباشرة مع نظام فرعي معقد.

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

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

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

على سبيل المثال، لنعد إلى إطار عمل تحويل الفيديو الخاص بنا. يمكن تقسيمه إلى طبقتين: واحدة تتعلق بالفيديو وأخرى بالصوت. يمكنك لكل طبقة إنشاء واجهة، ثم جعل فئات كل طبقة تتواصل مع بعضها عبر تلك الواجهات. يشبه هذا النهج إلى حد كبير نمط [الوسيط (Mediator)](/ar/design-patterns/mediator).

## How to Implement

1. تحقق مما إذا كان بالإمكان توفير واجهة أبسط مما يوفره النظام الفرعي الحالي بالفعل. أنت على الطريق الصحيح إذا كانت هذه الواجهة تجعل كود العميل مستقلاً عن كثير من فئات النظام الفرعي.
2. أعلن عن هذه الواجهة ونفّذها في فئة واجهة جديدة. يجب أن تعيد الواجهة توجيه الاستدعاءات من كود العميل إلى الكائنات المناسبة في النظام الفرعي. ينبغي أن تكون الواجهة مسؤولة عن تهيئة النظام الفرعي وإدارة دورة حياته اللاحقة ما لم يكن كود العميل يتولى ذلك مسبقًا.
3. للاستفادة الكاملة من النمط، اجعل جميع كود العميل يتواصل مع النظام الفرعي فقط عبر الواجهة. الآن أصبح كود العميل محميًا من أي تغييرات في كود النظام الفرعي. على سبيل المثال، عند ترقية النظام الفرعي إلى إصدار جديد، ستحتاج فقط إلى تعديل الكود في الواجهة.
4. إذا أصبحت الواجهة [كبيرة جدًا](/ar/smells/large-class)، فكّر في استخراج جزء من سلوكها إلى فئة واجهة جديدة ومحسّنة.

## Pros

* يمكنك عزل الكود الخاص بك عن تعقيدات النظام الفرعي.

## Cons

* يمكن أن تصبح الواجهة [كائن إله (god object)](/ar/antipatterns/god-object) مقترنًا بجميع فئات التطبيق.

## Relations with Other Patterns

* [الواجهة (Facade)](/ar/design-patterns/facade) تُعرّف واجهة جديدة للكائنات الموجودة، في حين يحاول [المهايئ (Adapter)](/ar/design-patterns/adapter) جعل الواجهة الحالية قابلة للاستخدام. عادةً ما يلف _المهايئ_ كائنًا واحدًا فقط، بينما تعمل _الواجهة_ مع نظام فرعي كامل من الكائنات.
* يمكن أن يكون [المصنع المجرد (Abstract Factory)](/ar/design-patterns/abstract-factory) بديلاً لـ [الواجهة (Facade)](/ar/design-patterns/facade) عندما تريد فقط إخفاء طريقة إنشاء كائنات النظام الفرعي من كود العميل.
* يُوضح [الكائن الخفيف (Flyweight)](/ar/design-patterns/flyweight) كيفية إنشاء كميات كبيرة من الكائنات الصغيرة، بينما تُوضح [الواجهة (Facade)](/ar/design-patterns/facade) كيفية إنشاء كائن واحد يمثل نظامًا فرعيًا بأكمله.
* تؤدي [الواجهة (Facade)](/ar/design-patterns/facade) و[الوسيط (Mediator)](/ar/design-patterns/mediator) وظائف متشابهة: كلاهما يحاول تنظيم التعاون بين فئات كثيرة مترابطة بإحكام.

  * تُعرّف _الواجهة_ واجهة مبسطة لنظام فرعي من الكائنات، لكنها لا تُدخل أي وظائف جديدة. النظام الفرعي نفسه لا يعرف بوجود الواجهة. يمكن للكائنات داخل النظام الفرعي التواصل مباشرة مع بعضها.
  * يُمركز _الوسيط_ التواصل بين مكوّنات النظام. المكوّنات تعرف فقط كائن الوسيط ولا تتواصل مباشرة.
* يمكن في أغلب الأحيان تحويل فئة [الواجهة (Facade)](/ar/design-patterns/facade) إلى [المفرد (Singleton)](/ar/design-patterns/singleton) نظرًا لأن كائن واجهة واحدًا يكفي في معظم الحالات.
* تتشابه [الواجهة (Facade)](/ar/design-patterns/facade) مع [الوكيل (Proxy)](/ar/design-patterns/proxy) في أن كليهما يُضيف طبقة حاجزة أمام كيان معقد ويُهيئه بشكل مستقل. على عكس _الواجهة_، يمتلك _الوكيل_ نفس الواجهة التي يمتلكها كائن الخدمة، مما يجعلهما قابلَين للتبادل.
## Relations

**Related patterns**

- [المهايئ (Adapter)](/ar/design-patterns/adapter.md)
- [المصنع المجرد (Abstract Factory)](/ar/design-patterns/abstract-factory.md)
- [وزن الذبابة](/ar/design-patterns/flyweight.md)
- [الوسيط](/ar/design-patterns/mediator.md)
- [Singleton](/ar/design-patterns/singleton.md)
- [الوكيل](/ar/design-patterns/proxy.md)

## Code Examples

### java

```java
package refactoring_guru.facade.example.some_complex_media_library;

public class VideoFile {
    private String name;
    private String codecType;

    public VideoFile(String name) {
        this.name = name;
        this.codecType = name.substring(name.indexOf(".") + 1);
    }

    public String getCodecType() {
        return codecType;
    }

    public String getName() {
        return name;
    }
}

package refactoring_guru.facade.example.some_complex_media_library;

public interface Codec {
}

package refactoring_guru.facade.example.some_complex_media_library;

public class MPEG4CompressionCodec implements Codec {
    public String type = "mp4";

}

package refactoring_guru.facade.example.some_complex_media_library;

public class OggCompressionCodec implements Codec {
    public String type = "ogg";
}

package refactoring_guru.facade.example.some_complex_media_library;

public class CodecFactory {
    public static Codec extract(VideoFile file) {
        String type = file.getCodecType();
        if (type.equals("mp4")) {
            System.out.println("CodecFactory: extracting mpeg audio...");
            return new MPEG4CompressionCodec();
        }
        else {
            System.out.println("CodecFactory: extracting ogg audio...");
            return new OggCompressionCodec();
        }
    }
}

package refactoring_guru.facade.example.some_complex_media_library;

public class BitrateReader {
    public static VideoFile read(VideoFile file, Codec codec) {
        System.out.println("BitrateReader: reading file...");
        return file;
    }

    public static VideoFile convert(VideoFile buffer, Codec codec) {
        System.out.println("BitrateReader: writing file...");
        return buffer;
    }
}

package refactoring_guru.facade.example.some_complex_media_library;

import java.io.File;

public class AudioMixer {
    public File fix(VideoFile result){
        System.out.println("AudioMixer: fixing audio...");
        return new File("tmp");
    }
}

package refactoring_guru.facade.example.facade;

import refactoring_guru.facade.example.some_complex_media_library.*;

import java.io.File;

public class VideoConversionFacade {
    public File convertVideo(String fileName, String format) {
        System.out.println("VideoConversionFacade: conversion started.");
        VideoFile file = new VideoFile(fileName);
        Codec sourceCodec = CodecFactory.extract(file);
        Codec destinationCodec;
        if (format.equals("mp4")) {
            destinationCodec = new MPEG4CompressionCodec();
        } else {
            destinationCodec = new OggCompressionCodec();
        }
        VideoFile buffer = BitrateReader.read(file, sourceCodec);
        VideoFile intermediateResult = BitrateReader.convert(buffer, destinationCodec);
        File result = (new AudioMixer()).fix(intermediateResult);
        System.out.println("VideoConversionFacade: conversion completed.");
        return result;
    }
}

package refactoring_guru.facade.example;

import refactoring_guru.facade.example.facade.VideoConversionFacade;

import java.io.File;

public class Demo {
    public static void main(String[] args) {
        VideoConversionFacade converter = new VideoConversionFacade();
        File mp4Video = converter.convertVideo("youtubevideo.ogg", "mp4");
        // ...
    }
}

VideoConversionFacade: conversion started.
CodecFactory: extracting ogg audio...
BitrateReader: reading file...
BitrateReader: writing file...
AudioMixer: fixing audio...
VideoConversionFacade: conversion completed.
```

### csharp

```csharp
using System;

namespace RefactoringGuru.DesignPatterns.Facade.Conceptual
{
    // توفر فئة الواجهة (Facade) واجهة بسيطة للمنطق المعقد لنظام فرعي واحد
    // أو عدة أنظمة فرعية. تُحيل الواجهة طلبات العميل إلى الكائنات
    // المناسبة داخل النظام الفرعي. كما أنها مسؤولة
    // عن إدارة دورة حياتها. كل هذا يحمي العميل من
    // التعقيد غير المرغوب فيه للنظام الفرعي.
    public class Facade
    {
        protected Subsystem1 _subsystem1;
		
        protected Subsystem2 _subsystem2;

        public Facade(Subsystem1 subsystem1, Subsystem2 subsystem2)
        {
            this._subsystem1 = subsystem1;
            this._subsystem2 = subsystem2;
        }
		
        // أساليب الواجهة عبارة عن اختصارات ملائمة للوظائف المتطورة
        // للأنظمة الفرعية. غير أن العملاء يصلون فقط إلى
        // جزء من قدرات النظام الفرعي.
        public string Operation()
        {
            string result = "Facade initializes subsystems:\n";
            result += this._subsystem1.operation1();
            result += this._subsystem2.operation1();
            result += "Facade orders subsystems to perform the action:\n";
            result += this._subsystem1.operationN();
            result += this._subsystem2.operationZ();
            return result;
        }
    }
    
    // يمكن للنظام الفرعي قبول الطلبات إما من الواجهة أو من العميل
    // مباشرة. في كلتا الحالتين، تُعدّ الواجهة بالنسبة للنظام الفرعي
    // مجرد عميل آخر، وليست جزءًا من النظام الفرعي.
    public class Subsystem1
    {
        public string operation1()
        {
            return "Subsystem1: Ready!\n";
        }

        public string operationN()
        {
            return "Subsystem1: Go!\n";
        }
    }
	
    // يمكن لبعض الواجهات العمل مع أنظمة فرعية متعددة في نفس الوقت.
    public class Subsystem2
    {
        public string operation1()
        {
            return "Subsystem2: Get ready!\n";
        }

        public string operationZ()
        {
            return "Subsystem2: Fire!\n";
        }
    }


    class Client
    {
        // يعمل كود العميل مع الأنظمة الفرعية المعقدة من خلال واجهة بسيطة
        // توفرها الواجهة (Facade). عندما تُدير الواجهة دورة حياة النظام الفرعي،
        // قد لا يعرف العميل حتى بوجود النظام الفرعي. يتيح
        // لك هذا النهج إبقاء التعقيد تحت السيطرة.
        public static void ClientCode(Facade facade)
        {
            Console.Write(facade.Operation());
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            // قد يكون لدى كود العميل بعض كائنات النظام الفرعي التي تم إنشاؤها مسبقًا.
            // في هذه الحالة، قد يكون من المفيد تهيئة الواجهة بهذه الكائنات
            // بدلاً من السماح للواجهة بإنشاء
            // نسخ جديدة.
            Subsystem1 subsystem1 = new Subsystem1();
            Subsystem2 subsystem2 = new Subsystem2();
            Facade facade = new Facade(subsystem1, subsystem2);
            Client.ClientCode(facade);
        }
    }
}

Facade initializes subsystems:
Subsystem1: Ready!
Subsystem2: Get ready!
Facade orders subsystems to perform the action:
Subsystem1: Go!
Subsystem2: Fire!
```

### cpp

```cpp
/**
 * يمكن للنظام الفرعي قبول الطلبات إما من الواجهة أو من العميل مباشرة.
 * في كلتا الحالتين، تُعدّ الواجهة بالنسبة للنظام الفرعي مجرد عميل آخر،
 * وليست جزءًا من النظام الفرعي.
 */
class Subsystem1 {
 public:
  std::string Operation1() const {
    return "Subsystem1: Ready!\n";
  }
  // ...
  std::string OperationN() const {
    return "Subsystem1: Go!\n";
  }
};
/**
 * يمكن لبعض الواجهات العمل مع أنظمة فرعية متعددة في نفس الوقت.
 */
class Subsystem2 {
 public:
  std::string Operation1() const {
    return "Subsystem2: Get ready!\n";
  }
  // ...
  std::string OperationZ() const {
    return "Subsystem2: Fire!\n";
  }
};

/**
 * توفر فئة الواجهة (Facade) واجهة بسيطة للمنطق المعقد لنظام فرعي واحد أو
 * عدة أنظمة فرعية. تُحيل الواجهة طلبات العميل إلى الكائنات
 * المناسبة داخل النظام الفرعي. كما أنها مسؤولة عن
 * إدارة دورة حياتها. كل هذا يحمي العميل من التعقيد
 * غير المرغوب فيه للنظام الفرعي.
 */
class Facade {
 protected:
  Subsystem1 *subsystem1_;
  Subsystem2 *subsystem2_;
  /**
   * بناءً على احتياجات تطبيقك، يمكنك تزويد الواجهة بكائنات النظام الفرعي
   * الموجودة أو إجبار الواجهة على إنشائها بنفسها.
   */
 public:
  /**
   * في هذه الحالة سنفوّض ملكية الذاكرة إلى فئة الواجهة
   */
  Facade(
      Subsystem1 *subsystem1 = nullptr,
      Subsystem2 *subsystem2 = nullptr) {
    this->subsystem1_ = subsystem1 ?: new Subsystem1;
    this->subsystem2_ = subsystem2 ?: new Subsystem2;
  }
  ~Facade() {
    delete subsystem1_;
    delete subsystem2_;
  }
  /**
   * أساليب الواجهة عبارة عن اختصارات ملائمة للوظائف المتطورة
   * للأنظمة الفرعية. غير أن العملاء يصلون فقط إلى جزء من
   * قدرات النظام الفرعي.
   */
  std::string Operation() {
    std::string result = "Facade initializes subsystems:\n";
    result += this->subsystem1_->Operation1();
    result += this->subsystem2_->Operation1();
    result += "Facade orders subsystems to perform the action:\n";
    result += this->subsystem1_->OperationN();
    result += this->subsystem2_->OperationZ();
    return result;
  }
};

/**
 * يعمل كود العميل مع الأنظمة الفرعية المعقدة من خلال واجهة بسيطة
 * توفرها الواجهة (Facade). عندما تُدير الواجهة دورة حياة النظام الفرعي،
 * قد لا يعرف العميل حتى بوجود النظام الفرعي. يتيح
 * لك هذا النهج إبقاء التعقيد تحت السيطرة.
 */
void ClientCode(Facade *facade) {
  // ...
  std::cout << facade->Operation();
  // ...
}
/**
 * قد يكون لدى كود العميل بعض كائنات النظام الفرعي التي تم إنشاؤها مسبقًا. في
 * هذه الحالة، قد يكون من المفيد تهيئة الواجهة بهذه الكائنات
 * بدلاً من السماح للواجهة بإنشاء نسخ جديدة.
 */

int main() {
  Subsystem1 *subsystem1 = new Subsystem1;
  Subsystem2 *subsystem2 = new Subsystem2;
  Facade *facade = new Facade(subsystem1, subsystem2);
  ClientCode(facade);

  delete facade;

  return 0;
}

Facade initializes subsystems:
Subsystem1: Ready!
Subsystem2: Get ready!
Facade orders subsystems to perform the action:
Subsystem1: Go!
Subsystem2: Fire!
```

### go

```go
package main

import "fmt"

type WalletFacade struct {
	account      *Account
	wallet       *Wallet
	securityCode *SecurityCode
	notification *Notification
	ledger       *Ledger
}

func newWalletFacade(accountID string, code int) *WalletFacade {
	fmt.Println("Starting create account")
	walletFacacde := &WalletFacade{
		account:      newAccount(accountID),
		securityCode: newSecurityCode(code),
		wallet:       newWallet(),
		notification: &Notification{},
		ledger:       &Ledger{},
	}
	fmt.Println("Account created")
	return walletFacacde
}

func (w *WalletFacade) addMoneyToWallet(accountID string, securityCode int, amount int) error {
	fmt.Println("Starting add money to wallet")
	err := w.account.checkAccount(accountID)
	if err != nil {
		return err
	}
	err = w.securityCode.checkCode(securityCode)
	if err != nil {
		return err
	}
	w.wallet.creditBalance(amount)
	w.notification.sendWalletCreditNotification()
	w.ledger.makeEntry(accountID, "credit", amount)
	return nil
}

func (w *WalletFacade) deductMoneyFromWallet(accountID string, securityCode int, amount int) error {
	fmt.Println("Starting debit money from wallet")
	err := w.account.checkAccount(accountID)
	if err != nil {
		return err
	}

	err = w.securityCode.checkCode(securityCode)
	if err != nil {
		return err
	}
	err = w.wallet.debitBalance(amount)
	if err != nil {
		return err
	}
	w.notification.sendWalletDebitNotification()
	w.ledger.makeEntry(accountID, "debit", amount)
	return nil
}

package main

import "fmt"

type Account struct {
	name string
}

func newAccount(accountName string) *Account {
	return &Account{
		name: accountName,
	}
}

func (a *Account) checkAccount(accountName string) error {
	if a.name != accountName {
		return fmt.Errorf("Account Name is incorrect")
	}
	fmt.Println("Account Verified")
	return nil
}

package main

import "fmt"

type SecurityCode struct {
	code int
}

func newSecurityCode(code int) *SecurityCode {
	return &SecurityCode{
		code: code,
	}
}

func (s *SecurityCode) checkCode(incomingCode int) error {
	if s.code != incomingCode {
		return fmt.Errorf("Security Code is incorrect")
	}
	fmt.Println("SecurityCode Verified")
	return nil
}

package main

import "fmt"

type Wallet struct {
	balance int
}

func newWallet() *Wallet {
	return &Wallet{
		balance: 0,
	}
}

func (w *Wallet) creditBalance(amount int) {
	w.balance += amount
	fmt.Println("Wallet balance added successfully")
	return
}

func (w *Wallet) debitBalance(amount int) error {
	if w.balance < amount {
		return fmt.Errorf("Balance is not sufficient")
	}
	fmt.Println("Wallet balance is Sufficient")
	w.balance = w.balance - amount
	return nil
}

package main

import "fmt"

type Ledger struct {
}

func (s *Ledger) makeEntry(accountID, txnType string, amount int) {
	fmt.Printf("Make ledger entry for accountId %s with txnType %s for amount %d\n", accountID, txnType, amount)
	return
}

package main

import "fmt"

type Notification struct {
}

func (n *Notification) sendWalletCreditNotification() {
	fmt.Println("Sending wallet credit notification")
}

func (n *Notification) sendWalletDebitNotification() {
	fmt.Println("Sending wallet debit notification")
}

package main

import (
	"fmt"
	"log"
)

func main() {
	fmt.Println()
	walletFacade := newWalletFacade("abc", 1234)
	fmt.Println()

	err := walletFacade.addMoneyToWallet("abc", 1234, 10)
	if err != nil {
		log.Fatalf("Error: %s\n", err.Error())
	}

	fmt.Println()
	err = walletFacade.deductMoneyFromWallet("abc", 1234, 5)
	if err != nil {
		log.Fatalf("Error: %s\n", err.Error())
	}
}

Starting create account
Account created

Starting add money to wallet
Account Verified
SecurityCode Verified
Wallet balance added successfully
Sending wallet credit notification
Make ledger entry for accountId abc with txnType credit for amount 10

Starting debit money from wallet
Account Verified
SecurityCode Verified
Wallet balance is Sufficient
Sending wallet debit notification
Make ledger entry for accountId abc with txnType debit for amount 5
```

### php

```php
<?php

namespace RefactoringGuru\Facade\Conceptual;

/**
 * توفر فئة الواجهة (Facade) واجهة بسيطة للمنطق المعقد لنظام فرعي واحد أو
 * عدة أنظمة فرعية. تُحيل الواجهة طلبات العميل إلى الكائنات
 * المناسبة داخل النظام الفرعي. كما أنها مسؤولة عن
 * إدارة دورة حياتها. كل هذا يحمي العميل من التعقيد
 * غير المرغوب فيه للنظام الفرعي.
 */
class Facade
{
    protected $subsystem1;

    protected $subsystem2;

    /**
     * بناءً على احتياجات تطبيقك، يمكنك تزويد الواجهة بكائنات النظام الفرعي
     * الموجودة أو إجبار الواجهة على إنشائها بنفسها.
     */
    public function __construct(
        Subsystem1 $subsystem1 = null,
        Subsystem2 $subsystem2 = null
    ) {
        $this->subsystem1 = $subsystem1 ?: new Subsystem1();
        $this->subsystem2 = $subsystem2 ?: new Subsystem2();
    }

    /**
     * أساليب الواجهة عبارة عن اختصارات ملائمة للوظائف المتطورة
     * للأنظمة الفرعية. غير أن العملاء يصلون فقط إلى جزء
     * من قدرات النظام الفرعي.
     */
    public function operation(): string
    {
        $result = "Facade initializes subsystems:\n";
        $result .= $this->subsystem1->operation1();
        $result .= $this->subsystem2->operation1();
        $result .= "Facade orders subsystems to perform the action:\n";
        $result .= $this->subsystem1->operationN();
        $result .= $this->subsystem2->operationZ();

        return $result;
    }
}

/**
 * يمكن للنظام الفرعي قبول الطلبات إما من الواجهة أو من العميل مباشرة.
 * في كلتا الحالتين، تُعدّ الواجهة بالنسبة للنظام الفرعي مجرد عميل آخر،
 * وليست جزءًا من النظام الفرعي.
 */
class Subsystem1
{
    public function operation1(): string
    {
        return "Subsystem1: Ready!\n";
    }

    // ...

    public function operationN(): string
    {
        return "Subsystem1: Go!\n";
    }
}

/**
 * يمكن لبعض الواجهات العمل مع أنظمة فرعية متعددة في نفس الوقت.
 */
class Subsystem2
{
    public function operation1(): string
    {
        return "Subsystem2: Get ready!\n";
    }

    // ...

    public function operationZ(): string
    {
        return "Subsystem2: Fire!\n";
    }
}

/**
 * يعمل كود العميل مع الأنظمة الفرعية المعقدة من خلال واجهة بسيطة
 * توفرها الواجهة (Facade). عندما تُدير الواجهة دورة حياة النظام الفرعي،
 * قد لا يعرف العميل حتى بوجود النظام الفرعي. يتيح
 * لك هذا النهج إبقاء التعقيد تحت السيطرة.
 */
function clientCode(Facade $facade)
{
    // ...

    echo $facade->operation();

    // ...
}

/**
 * قد يكون لدى كود العميل بعض كائنات النظام الفرعي التي تم إنشاؤها مسبقًا. في
 * هذه الحالة، قد يكون من المفيد تهيئة الواجهة بهذه الكائنات
 * بدلاً من السماح للواجهة بإنشاء نسخ جديدة.
 */
$subsystem1 = new Subsystem1();
$subsystem2 = new Subsystem2();
$facade = new Facade($subsystem1, $subsystem2);
clientCode($facade);

Facade initializes subsystems:
Subsystem1: Ready!
Subsystem2: Get ready!
Facade orders subsystems to perform the action:
Subsystem1: Go!
Subsystem2: Fire!

<?php

namespace RefactoringGuru\Facade\RealWorld;

/**
 * توفر الواجهة أسلوبًا واحدًا لتنزيل مقاطع الفيديو من YouTube. يُخفي
 * هذا الأسلوب كل تعقيدات طبقة الشبكة في PHP وواجهة YouTube API
 * ومكتبة تحويل الفيديو (FFmpeg).
 */
class YouTubeDownloader
{
    protected $youtube;
    protected $ffmpeg;

    /**
     * It is handy when the Facade can manage the lifecycle of the subsystem it
     * uses.
     */
    public function __construct(string $youtubeApiKey)
    {
        $this->youtube = new YouTube($youtubeApiKey);
        $this->ffmpeg = new FFMpeg();
    }

    /**
     * The Facade provides a simple method for downloading video and encoding it
     * to a target format (for the sake of simplicity, the real-world code is
     * commented-out).
     */
    public function downloadVideo(string $url): void
    {
        echo "Fetching video metadata from youtube...\n";
        // $title = $this->youtube->fetchVideo($url)->getTitle();
        echo "Saving video file to a temporary file...\n";
        // $this->youtube->saveAs($url, "video.mpg");

        echo "Processing source video...\n";
        // $video = $this->ffmpeg->open('video.mpg');
        echo "Normalizing and resizing the video to smaller dimensions...\n";
        // $video
        //     ->filters()
        //     ->resize(new FFMpeg\Coordinate\Dimension(320, 240))
        //     ->synchronize();
        echo "Capturing preview image...\n";
        // $video
        //     ->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(10))
        //     ->save($title . 'frame.jpg');
        echo "Saving video in target formats...\n";
        // $video
        //     ->save(new FFMpeg\Format\Video\X264(), $title . '.mp4')
        //     ->save(new FFMpeg\Format\Video\WMV(), $title . '.wmv')
        //     ->save(new FFMpeg\Format\Video\WebM(), $title . '.webm');
        echo "Done!\n";
    }
}

/**
 * نظام YouTube API الفرعي.
 */
class YouTube
{
    public function fetchVideo(): string
    {
      /* ... */
    }

    public function saveAs(string $path): void
    {
      /* ... */
    }

    // ...more methods and classes...
}

/**
 * النظام الفرعي FFmpeg (مكتبة تحويل الفيديو/الصوت المعقدة).
 */
class FFMpeg
{
    public static function create(): FFMpeg
    {
      /* ... */
    }

    public function open(string $video): void
    {
      /* ... */
    }

    // ...المزيد من الأساليب والفئات...
}

class FFMpegVideo
{
    public function filters(): self
    {
      /* ... */
    }

    public function resize(): self
    {
      /* ... */
    }

    public function synchronize(): self
    {
      /* ... */
    }

    public function frame(): self
    {
      /* ... */
    }

    public function save(string $path): self
    {
      /* ... */
    }

    // ...المزيد من الأساليب والفئات...
}


/**
 * كود العميل لا يعتمد على أي فئات من النظام الفرعي. لن تؤثر أي تغييرات
 * داخل كود النظام الفرعي على كود العميل. ستحتاج فقط
 * إلى تحديث الواجهة.
 */
function clientCode(YouTubeDownloader $facade)
{
    // ...

    $facade->downloadVideo("https://www.youtube.com/watch?v=QH2-TGUlwu4");

    // ...
}

$facade = new YouTubeDownloader("APIKEY-XXXXXXXXX");
clientCode($facade);

Fetching video metadata from youtube...
Saving video file to a temporary file...
Processing source video...
Normalizing and resizing the video to smaller dimensions...
Capturing preview image...
Saving video in target formats...
Done!
```

### python

```python
from __future__ import annotations


class Facade:
    """
    توفر فئة الواجهة (Facade) واجهة بسيطة للمنطق المعقد لنظام فرعي واحد أو
    عدة أنظمة فرعية. تُحيل الواجهة طلبات العميل إلى الكائنات
    المناسبة داخل النظام الفرعي. كما أنها مسؤولة عن إدارة دورة حياتها.
    كل هذا يحمي العميل من التعقيد غير المرغوب فيه للنظام الفرعي.
    """

    def __init__(self, subsystem1: Subsystem1, subsystem2: Subsystem2) -> None:
        """
        بناءً على احتياجات تطبيقك، يمكنك تزويد الواجهة بكائنات النظام الفرعي
        الموجودة أو إجبار الواجهة على إنشائها بنفسها.
        """

        self._subsystem1 = subsystem1 or Subsystem1()
        self._subsystem2 = subsystem2 or Subsystem2()

    def operation(self) -> str:
        """
        أساليب الواجهة عبارة عن اختصارات ملائمة للوظائف المتطورة
        للأنظمة الفرعية. غير أن العملاء يصلون فقط إلى جزء
        من قدرات النظام الفرعي.
        """

        results = []
        results.append("Facade initializes subsystems:")
        results.append(self._subsystem1.operation1())
        results.append(self._subsystem2.operation1())
        results.append("Facade orders subsystems to perform the action:")
        results.append(self._subsystem1.operation_n())
        results.append(self._subsystem2.operation_z())
        return "\n".join(results)


class Subsystem1:
    """
    يمكن للنظام الفرعي قبول الطلبات إما من الواجهة أو من العميل مباشرة.
    في كلتا الحالتين، تُعدّ الواجهة بالنسبة للنظام الفرعي مجرد عميل آخر،
    وليست جزءًا من النظام الفرعي.
    """

    def operation1(self) -> str:
        return "Subsystem1: Ready!"

    # ...

    def operation_n(self) -> str:
        return "Subsystem1: Go!"


class Subsystem2:
    """
    يمكن لبعض الواجهات العمل مع أنظمة فرعية متعددة في نفس الوقت.
    """

    def operation1(self) -> str:
        return "Subsystem2: Get ready!"

    # ...

    def operation_z(self) -> str:
        return "Subsystem2: Fire!"


def client_code(facade: Facade) -> None:
    """
    يعمل كود العميل مع الأنظمة الفرعية المعقدة من خلال واجهة بسيطة
    توفرها الواجهة (Facade). عندما تُدير الواجهة دورة حياة النظام الفرعي،
    قد لا يعرف العميل حتى بوجود النظام الفرعي. يتيح لك
    هذا النهج إبقاء التعقيد تحت السيطرة.
    """

    print(facade.operation(), end="")


if __name__ == "__main__":
    # قد يكون لدى كود العميل بعض كائنات النظام الفرعي التي تم إنشاؤها مسبقًا.
    # في هذه الحالة، قد يكون من المفيد تهيئة الواجهة بهذه الكائنات
    # بدلاً من السماح للواجهة بإنشاء نسخ جديدة.
    subsystem1 = Subsystem1()
    subsystem2 = Subsystem2()
    facade = Facade(subsystem1, subsystem2)
    client_code(facade)

Facade initializes subsystems:
Subsystem1: Ready!
Subsystem2: Get ready!
Facade orders subsystems to perform the action:
Subsystem1: Go!
Subsystem2: Fire!
```

### ruby

```ruby
# توفر فئة الواجهة (Facade) واجهة بسيطة للمنطق المعقد لنظام فرعي واحد أو
# عدة أنظمة فرعية. تُحيل الواجهة طلبات العميل إلى الكائنات
# المناسبة داخل النظام الفرعي. كما أنها مسؤولة عن
# إدارة دورة حياتها. كل هذا يحمي العميل من التعقيد
# غير المرغوب فيه للنظام الفرعي.
class Facade
  # بناءً على احتياجات تطبيقك، يمكنك تزويد الواجهة بكائنات النظام الفرعي
  # الموجودة أو إجبار الواجهة على إنشائها بنفسها.
  def initialize(subsystem1, subsystem2)
    @subsystem1 = subsystem1 || Subsystem1.new
    @subsystem2 = subsystem2 || Subsystem2.new
  end

  # أساليب الواجهة عبارة عن اختصارات ملائمة للوظائف المتطورة
  # للأنظمة الفرعية. غير أن العملاء يصلون فقط إلى جزء من
  # قدرات النظام الفرعي.
  def operation
    results = []
    results.append('Facade initializes subsystems:')
    results.append(@subsystem1.operation1)
    results.append(@subsystem2.operation1)
    results.append('Facade orders subsystems to perform the action:')
    results.append(@subsystem1.operation_n)
    results.append(@subsystem2.operation_z)
    results.join("\n")
  end
end

# يمكن للنظام الفرعي قبول الطلبات إما من الواجهة أو من العميل مباشرة.
# في كلتا الحالتين، تُعدّ الواجهة بالنسبة للنظام الفرعي مجرد عميل آخر،
# وليست جزءًا من النظام الفرعي.
class Subsystem1
  # @return [String]
  def operation1
    'Subsystem1: Ready!'
  end

  # ...

  # @return [String]
  def operation_n
    'Subsystem1: Go!'
  end
end

# يمكن لبعض الواجهات العمل مع أنظمة فرعية متعددة في نفس الوقت.
class Subsystem2
  # @return [String]
  def operation1
    'Subsystem2: Get ready!'
  end

  # ...

  # @return [String]
  def operation_z
    'Subsystem2: Fire!'
  end
end

# يعمل كود العميل مع الأنظمة الفرعية المعقدة من خلال واجهة بسيطة
# توفرها الواجهة (Facade). عندما تُدير الواجهة دورة حياة النظام الفرعي،
# قد لا يعرف العميل حتى بوجود النظام الفرعي. يتيح
# لك هذا النهج إبقاء التعقيد تحت السيطرة.
def client_code(facade)
  print facade.operation
end

# قد يكون لدى كود العميل بعض كائنات النظام الفرعي التي تم إنشاؤها مسبقًا. في
# هذه الحالة، قد يكون من المفيد تهيئة الواجهة بهذه الكائنات
# بدلاً من السماح للواجهة بإنشاء نسخ جديدة.
subsystem1 = Subsystem1.new
subsystem2 = Subsystem2.new
facade = Facade.new(subsystem1, subsystem2)
client_code(facade)

Facade initializes subsystems:
Subsystem1: Ready!
Subsystem2: Get ready!
Facade orders subsystems to perform the action:
Subsystem1: Go!
Subsystem2: Fire!
```

### rust

```rust
use crate::{
    account::Account, ledger::Ledger, notification::Notification, security_code::SecurityCode,
    wallet::Wallet,
};

/// الواجهة (Facade) تُخفي منطقًا معقدًا خلف الـ API.
pub struct WalletFacade {
    account: Account,
    wallet: Wallet,
    code: SecurityCode,
    notification: Notification,
    ledger: Ledger,
}

impl WalletFacade {
    pub fn new(account_id: String, code: u32) -> Self {
        println!("Starting create account");

        let this = Self {
            account: Account::new(account_id),
            wallet: Wallet::new(),
            code: SecurityCode::new(code),
            notification: Notification,
            ledger: Ledger,
        };

        println!("Account created");
        this
    }

    pub fn add_money_to_wallet(
        &mut self,
        account_id: &String,
        security_code: u32,
        amount: u32,
    ) -> Result<(), String> {
        println!("Starting add money to wallet");
        self.account.check(account_id)?;
        self.code.check(security_code)?;
        self.wallet.credit_balance(amount);
        self.notification.send_wallet_credit_notification();
        self.ledger.make_entry(account_id, "credit".into(), amount);
        Ok(())
    }

    pub fn deduct_money_from_wallet(
        &mut self,
        account_id: &String,
        security_code: u32,
        amount: u32,
    ) -> Result<(), String> {
        println!("Starting debit money from wallet");
        self.account.check(account_id)?;
        self.code.check(security_code)?;
        self.wallet.debit_balance(amount);
        self.notification.send_wallet_debit_notification();
        self.ledger.make_entry(account_id, "debit".into(), amount);
        Ok(())
    }
}

pub struct Wallet {
    balance: u32,
}

impl Wallet {
    pub fn new() -> Self {
        Self { balance: 0 }
    }

    pub fn credit_balance(&mut self, amount: u32) {
        self.balance += amount;
    }

    pub fn debit_balance(&mut self, amount: u32) {
        self.balance
            .checked_sub(amount)
            .expect("Balance is not sufficient");
    }
}

pub struct Account {
    name: String,
}

impl Account {
    pub fn new(name: String) -> Self {
        Self { name }
    }

    pub fn check(&self, name: &String) -> Result<(), String> {
        if &self.name != name {
            return Err("Account name is incorrect".into());
        }

        println!("Account verified");
        Ok(())
    }
}

pub struct Ledger;

impl Ledger {
    pub fn make_entry(&mut self, account_id: &String, txn_type: String, amount: u32) {
        println!(
            "Make ledger entry for accountId {} with transaction type {} for amount {}",
            account_id, txn_type, amount
        );
    }
}

pub struct Notification;

impl Notification {
    pub fn send_wallet_credit_notification(&self) {
        println!("Sending wallet credit notification");
    }

    pub fn send_wallet_debit_notification(&self) {
        println!("Sending wallet debit notification");
    }
}

pub struct SecurityCode {
    code: u32,
}

impl SecurityCode {
    pub fn new(code: u32) -> Self {
        Self { code }
    }

    pub fn check(&self, code: u32) -> Result<(), String> {
        if self.code != code {
            return Err("Security code is incorrect".into());
        }

        println!("Security code verified");
        Ok(())
    }
}

mod account;
mod ledger;
mod notification;
mod security_code;
mod wallet;
mod wallet_facade;

use wallet_facade::WalletFacade;

fn main() -> Result<(), String> {
    let mut wallet = WalletFacade::new("abc".into(), 1234);
    println!();

    // تتفاعل واجهة المحفظة (WalletFacade) مع الحساب والرمز والمحفظة والإشعار
    // ودفتر الأستاذ في الخلفية.
    wallet.add_money_to_wallet(&"abc".into(), 1234, 10)?;
    println!();

    wallet.deduct_money_from_wallet(&"abc".into(), 1234, 5)
}

Starting create account
Account created

Starting add money to wallet
Account verified
Security code verified
Sending wallet credit notification
Make ledger entry for accountId abc with transaction type credit for amount 10

Starting debit money from wallet
Account verified
Security code verified
Sending wallet debit notification
Make ledger entry for accountId abc with transaction type debit for amount 5
```

### swift

```swift
import XCTest

/// توفر فئة الواجهة (Facade) واجهة بسيطة للمنطق المعقد لنظام فرعي واحد أو
/// عدة أنظمة فرعية. تُحيل الواجهة طلبات العميل إلى الكائنات
/// المناسبة داخل النظام الفرعي. كما أنها مسؤولة عن
/// إدارة دورة حياتها. كل هذا يحمي العميل من التعقيد
/// غير المرغوب فيه للنظام الفرعي.
class Facade {

    private var subsystem1: Subsystem1
    private var subsystem2: Subsystem2

    /// بناءً على احتياجات تطبيقك، يمكنك تزويد الواجهة بكائنات النظام الفرعي
    /// الموجودة أو إجبار الواجهة على إنشائها بنفسها.
    init(subsystem1: Subsystem1 = Subsystem1(),
         subsystem2: Subsystem2 = Subsystem2()) {
        self.subsystem1 = subsystem1
        self.subsystem2 = subsystem2
    }

    /// أساليب الواجهة عبارة عن اختصارات ملائمة للوظائف المتطورة
    /// للأنظمة الفرعية. غير أن العملاء يصلون فقط إلى جزء
    /// من قدرات النظام الفرعي.
    func operation() -> String {

        var result = "Facade initializes subsystems:"
        result += " " + subsystem1.operation1()
        result += " " + subsystem2.operation1()
        result += "\n" + "Facade orders subsystems to perform the action:\n"
        result += " " + subsystem1.operationN()
        result += " " + subsystem2.operationZ()
        return result
    }
}

/// يمكن للنظام الفرعي قبول الطلبات إما من الواجهة أو من العميل مباشرة.
/// في كلتا الحالتين، تُعدّ الواجهة بالنسبة للنظام الفرعي مجرد عميل آخر،
/// وليست جزءًا من النظام الفرعي.
class Subsystem1 {

    func operation1() -> String {
        return "Subsystem1: Ready!\n"
    }

    // ...

    func operationN() -> String {
        return "Subsystem1: Go!\n"
    }
}

/// يمكن لبعض الواجهات العمل مع أنظمة فرعية متعددة في نفس الوقت.
class Subsystem2 {

    func operation1() -> String {
        return "Subsystem2: Get ready!\n"
    }

    // ...

    func operationZ() -> String {
        return "Subsystem2: Fire!\n"
    }
}

/// يعمل كود العميل مع الأنظمة الفرعية المعقدة من خلال واجهة بسيطة
/// توفرها الواجهة (Facade). عندما تُدير الواجهة دورة حياة النظام الفرعي،
/// قد لا يعرف العميل حتى بوجود النظام الفرعي. يتيح
/// لك هذا النهج إبقاء التعقيد تحت السيطرة.
class Client {
    // ...
    static func clientCode(facade: Facade) {
        print(facade.operation())
    }
    // ...
}

/// دعنا نرى كيف يعمل كل هذا معًا.
class FacadeConceptual: XCTestCase {

    func testFacadeConceptual() {

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

        let subsystem1 = Subsystem1()
        let subsystem2 = Subsystem2()
        let facade = Facade(subsystem1: subsystem1, subsystem2: subsystem2)
        Client.clientCode(facade: facade)
    }
}

Facade initializes subsystems: Sybsystem1: Ready!
Sybsystem2: Get ready!

Facade orders subsystems to perform the action:
Sybsystem1: Go!
Sybsystem2: Fire!

import XCTest

/// نمط تصميم الواجهة (Facade)
///
/// الغرض: توفير واجهة مبسطة لمكتبة أو إطار عمل أو أي
/// مجموعة معقدة أخرى من الفئات.

class FacadeRealWorld: XCTestCase {

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

    func testFacadeRealWorld() {

        let imageView = UIImageView()

        print("Let's set an image for the image view")

        clientCode(imageView)

        print("Image has been set")

        XCTAssert(imageView.image != nil)
    }

    fileprivate func clientCode(_ imageView: UIImageView) {

        let url = URL(string: "www.example.com/logo")
        imageView.downloadImage(at: url)
    }
}

private extension UIImageView {

    /// هذا الامتداد يؤدي دور الواجهة (Facade).

    func downloadImage(at url: URL?) {

        print("Start downloading...")

        let placeholder = UIImage(named: "placeholder")

        ImageDownloader().loadImage(at: url,
                                    placeholder: placeholder,
                                    completion: { image, error in
            print("Handle an image...")

            /// اقتص، خزّن مؤقتًا، طبّق الفلاتر، وما إلى ذلك...

            self.image = image
        })
    }
}

private class ImageDownloader {

    /// مكتبة طرف ثالث أو حلّك الخاص (النظام الفرعي)

    typealias Completion = (UIImage, Error?) -> ()
    typealias Progress = (Int, Int) -> ()

    func loadImage(at url: URL?,
                   placeholder: UIImage? = nil,
                   progress: Progress? = nil,
                   completion: Completion) {
        /// ... إعداد مكدّس الشبكة
        /// ... تنزيل صورة
        /// ...
        completion(UIImage(), nil)
    }
}

Let's set an image for the image view
Start downloading...
Handle an image...
Image has been set
```

### typescript

```typescript
/**
 * توفر فئة الواجهة (Facade) واجهة بسيطة للمنطق المعقد لنظام فرعي واحد أو
 * عدة أنظمة فرعية. تُحيل الواجهة طلبات العميل إلى الكائنات
 * المناسبة داخل النظام الفرعي. كما أنها مسؤولة عن
 * إدارة دورة حياتها. كل هذا يحمي العميل من التعقيد
 * غير المرغوب فيه للنظام الفرعي.
 */
class Facade {
    protected subsystem1: Subsystem1;

    protected subsystem2: Subsystem2;

    /**
     * بناءً على احتياجات تطبيقك، يمكنك تزويد الواجهة بكائنات النظام الفرعي
     * الموجودة أو إجبار الواجهة على إنشائها بنفسها.
     */
    constructor(subsystem1?: Subsystem1, subsystem2?: Subsystem2) {
        this.subsystem1 = subsystem1 || new Subsystem1();
        this.subsystem2 = subsystem2 || new Subsystem2();
    }

    /**
     * أساليب الواجهة عبارة عن اختصارات ملائمة للوظائف المتطورة
     * للأنظمة الفرعية. غير أن العملاء يصلون فقط إلى جزء
     * من قدرات النظام الفرعي.
     */
    public operation(): string {
        let result = 'Facade initializes subsystems:\n';
        result += this.subsystem1.operation1();
        result += this.subsystem2.operation1();
        result += 'Facade orders subsystems to perform the action:\n';
        result += this.subsystem1.operationN();
        result += this.subsystem2.operationZ();

        return result;
    }
}

/**
 * يمكن للنظام الفرعي قبول الطلبات إما من الواجهة أو من العميل مباشرة.
 * في كلتا الحالتين، تُعدّ الواجهة بالنسبة للنظام الفرعي مجرد عميل آخر،
 * وليست جزءًا من النظام الفرعي.
 */
class Subsystem1 {
    public operation1(): string {
        return 'Subsystem1: Ready!\n';
    }

    // ...

    public operationN(): string {
        return 'Subsystem1: Go!\n';
    }
}

/**
 * يمكن لبعض الواجهات العمل مع أنظمة فرعية متعددة في نفس الوقت.
 */
class Subsystem2 {
    public operation1(): string {
        return 'Subsystem2: Get ready!\n';
    }

    // ...

    public operationZ(): string {
        return 'Subsystem2: Fire!';
    }
}

/**
 * يعمل كود العميل مع الأنظمة الفرعية المعقدة من خلال واجهة بسيطة
 * توفرها الواجهة (Facade). عندما تُدير الواجهة دورة حياة النظام الفرعي،
 * قد لا يعرف العميل حتى بوجود النظام الفرعي. يتيح
 * لك هذا النهج إبقاء التعقيد تحت السيطرة.
 */
function clientCode(facade: Facade) {
    // ...

    console.log(facade.operation());

    // ...
}

/**
 * قد يكون لدى كود العميل بعض كائنات النظام الفرعي التي تم إنشاؤها مسبقًا. في
 * هذه الحالة، قد يكون من المفيد تهيئة الواجهة بهذه الكائنات
 * بدلاً من السماح للواجهة بإنشاء نسخ جديدة.
 */
const subsystem1 = new Subsystem1();
const subsystem2 = new Subsystem2();
const facade = new Facade(subsystem1, subsystem2);
clientCode(facade);

Facade initializes subsystems:
Subsystem1: Ready!
Subsystem2: Get ready!
Facade orders subsystems to perform the action:
Subsystem1: Go!
Subsystem2: Fire!
```

