---
title: "المصنع المجرد (Abstract Factory)"
type: "design-pattern"
slug: "abstract-factory"
url: "http://localhost:3000/ar/design-patterns/abstract-factory.md"
category: "الأنماط الإنشائية"
description: "المصنع المجرد (Abstract Factory) هو نمط تصميم إنشائي يتيح لك إنتاج عائلات من الكائنات ذات الصلة دون تحديد فئاتها الملموسة."
languages: ["java"]
---
# المصنع المجرد (Abstract Factory)

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

## الغرض

**المصنع المجرد** هو نمط تصميم إنشائي يتيح لك إنتاج عائلات من الكائنات ذات الصلة دون تحديد فئاتها الملموسة.

## المشكلة

تخيل أنك تقوم بإنشاء محاكي لمتجر أثاث. يتكون كودك من فئات تمثل:

1. عائلة من المنتجات ذات الصلة، مثلاً: `Chair` + `Sofa` + `CoffeeTable`.
2. عدة بدائل لهذه العائلة. على سبيل المثال، المنتجات `Chair` + `Sofa` + `CoffeeTable` متوفرة في هذه البدائل: `Modern` (حديث)، `Victorian` (فيكتوري)، `ArtDeco` (آرت ديكو).

عائلات المنتجات وبدائلها.

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

الأريكة ذات الطراز الحديث لا تتطابق مع الكراسي ذات الطراز الفيكتوري.

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

## الحل

أول شيء يقترحه نمط المصنع المجرد هو الإعلان صراحةً عن واجهات لكل منتج متميز في عائلة المنتجات (مثل الكرسي أو الأريكة أو طاولة القهوة). بعد ذلك، يمكنك جعل جميع بدائل المنتجات تتبع هذه الواجهات. على سبيل المثال، يمكن لجميع بدائل الكراسي تنفيذ واجهة `Chair`؛ ويمكن لجميع بدائل طاولة القهوة تنفيذ واجهة `CoffeeTable`، وهكذا.

يجب نقل جميع بدائل الكائن نفسه إلى تدرج هرمي واحد للفئات.

الخطوة التالية هي التصريح عن _المصنع المجرد_—واجهة تحتوي على قائمة بدوال الإنشاء لجميع المنتجات التي تعد جزءاً من عائلة المنتجات (على سبيل المثال، `createChair` و `createSofa` و `createCoffeeTable`). يجب أن ترجع هذه الدوال أنواع منتجات **مجردة** تمثلها الواجهات التي استخرجناها سابقاً: `Chair` و `Sofa` و `CoffeeTable` وما إلى ذلك.

يتوافق كل مصنع ملموس مع بديل منتج معين.

الآن، ماذا عن بدائل المنتج؟ لكل بديل من عائلة المنتجات، نقوم بإنشاء فئة مصنع منفصلة بناءً على واجهة `AbstractFactory`. المصنع هو فئة تعيد منتجات من نوع معين. على سبيل المثال، يمكن لـ `ModernFurnitureFactory` فقط إنشاء كائنات `ModernChair` و `ModernSofa` و `ModernCoffeeTable`.

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

لا ينبغي للعميل أن يهتم بالفئة الملموسة للمصنع الذي يعمل معه.

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

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

## الهيكل

1. **المنتجات المجردة (Abstract Products)** تعلن عن واجهات لمجموعة من المنتجات المتميزة ولكن ذات الصلة والتي تشكل عائلة منتجات.
2. **المنتجات الملموسة (Concrete Products)** هي تطبيقات مختلفة للمنتجات المجردة، مجمعة حسب البدائل. يجب تنفيذ كل منتج مجرد (كرسي/أريكة) في جميع البدائل المعطاة (فيكتوري/حديث).
3. تعلن واجهة **المصنع المجرد (Abstract Factory)** عن مجموعة من الدوال لإنشاء كل من المنتجات المجردة.
4. تقوم **المصانع الملموسة (Concrete Factories)** بتنفيذ دوال الإنشاء للمصنع المجرد. يتوافق كل مصنع ملموس مع بديل معين من المنتجات ويخلق فقط تلك البدائل للمنتجات.
5. على الرغم من أن المصانع الملموسة تنشئ منتجات ملموسة، إلا أن تواقيع دوال الإنشاء الخاصة بها يجب أن ترجع المنتجات _المجردة_ المقابلة. بهذه الطريقة لا يرتبط كود العميل الذي يستخدم المصنع بالبديل المحدد للمنتج الذي يحصل عليه من المصنع. يمكن لـ **العميل (Client)** العمل مع أي مصنع ملموس/بديل منتج، طالما أنه يتواصل مع كائناتها عبر الواجهات المجردة.

## الكود الوهمي (Pseudocode)

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

مثال على فئات واجهة المستخدم العابرة للمنصات.

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

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

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

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

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

// تعلن واجهة المصنع المجرد عن مجموعة من الدوال التي
// تعيد منتجات مجردة مختلفة. تسمى هذه المنتجات عائلة
// وترتبط بموضوع أو مفهوم عالي المستوى. عادةً ما تكون منتجات
// عائلة واحدة قادرة على التعاون فيما بينها. قد تحتوي عائلة
// المنتجات على عدة بدائل، ولكن منتجات بديل واحد غير متوافقة
// مع منتجات بديل آخر.
interface GUIFactory is
    method createButton():Button
    method createCheckbox():Checkbox

// تنتج المصانع الملموسة عائلة من المنتجات التي تنتمي
// إلى بديل واحد. يضمن المصنع أن المنتجات الناتجة متوافقة.
// ترجع تواقيع دوال المصنع الملموس منتجاً مجرداً،
// بينما داخل الدالة يتم إنشاء نسخة من منتج ملموس.
class WinFactory implements GUIFactory is
    method createButton():Button is
        return new WinButton()
    method createCheckbox():Checkbox is
        return new WinCheckbox()

// لكل مصنع ملموس بديل منتج مقابل.
class MacFactory implements GUIFactory is
    method createButton():Button is
        return new MacButton()
    method createCheckbox():Checkbox is
        return new MacCheckbox()

// يجب أن يكون لكل منتج متميز من عائلة منتجات واجهة
// أساسية. يجب أن تنفذ جميع بدائل المنتج هذه الواجهة.
interface Button is
    method paint()

// يتم إنشاء المنتجات الملموسة بواسطة المصانع الملموسة المقابلة.
class WinButton implements Button is
    method paint() is
        // تقديم زر بنمط Windows.

class MacButton implements Button is
    method paint() is
        // تقديم زر بنمط macOS.

// هذه هي الواجهة الأساسية لمنتج آخر. يمكن لجميع المنتجات
// التفاعل مع بعضها البعض، ولكن التفاعل المناسب ممكن فقط بين
// منتجات نفس البديل الملموس.
interface Checkbox is
    method paint()

class WinCheckbox implements Checkbox is
    method paint() is
        // تقديم خانة اختيار بنمط Windows.

class MacCheckbox implements Checkbox is
    method paint() is
        // تقديم خانة اختيار بنمط macOS.

// يعمل كود العميل مع المصانع والمنتجات فقط من خلال
// الأنواع المجردة: GUIFactory و Button و Checkbox. يتيح
// هذا تمرير أي فئة فرعية من المصنع أو المنتج إلى كود العميل دون كسرها.
class Application is
    private field factory: GUIFactory
    private field button: Button
    constructor Application(factory: GUIFactory) is
        this.factory = factory
    method createUI() is
        this.button = factory.createButton()
    method paint() is
        button.paint()

// يختار التطبيق نوع المصنع بناءً على التكوين الحالي أو
// إعدادات البيئة وينشئه في وقت التشغيل (عادةً في مرحلة التهيئة).
class ApplicationConfigurator is
    method main() is
        config = readApplicationConfigFile()

        if (config.OS == "Windows") then
            factory = new WinFactory()
        else if (config.OS == "Mac") then
            factory = new MacFactory()
        else
            throw new Exception("Error! Unknown operating system.")

        Application app = new Application(factory)

## التطبيق العملي

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

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

 فكر في تطبيق المصنع المجرد عندما يكون لديك فئة تحتوي على مجموعة من [دوال المصنع](/design-patterns/factory-method) التي تشوش على مسؤوليتها الأساسية.

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

## كيفية التنفيذ

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

## الإيجابيات

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

## السلبيات

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

## العلاقات مع الأنماط الأخرى

* تبدأ العديد من التصميمات باستخدام [دالة المصنع (Factory Method)](/design-patterns/factory-method) (أقل تعقيداً وأكثر قابلية للتخصيص عبر الفئات الفرعية) وتتطور نحو [المصنع المجرد (Abstract Factory)](/design-patterns/abstract-factory)، أو [النموذج الأولي (Prototype)](/design-patterns/prototype)، أو [الباني (Builder)](/design-patterns/builder) (أكثر مرونة، ولكنها أكثر تعقيداً).
* يركز [الباني (Builder)](/design-patterns/builder) على إنشاء كائنات معقدة خطوة بخطوة. يتخصص [المصنع المجرد (Abstract Factory)](/design-patterns/abstract-factory) في إنشاء عائلات من الكائنات ذات الصلة. يعيد _المصنع المجرد_ المنتج على الفور، بينما يسمح لك _الباني_ بتشغيل بعض خطوات البناء الإضافية قبل جلب المنتج.
* غالباً ما تعتمد فئات [المصنع المجرد (Abstract Factory)](/design-patterns/abstract-factory) على مجموعة من [دوال المصنع (Factory Methods)](/design-patterns/factory-method)، ولكن يمكنك أيضاً استخدام [النموذج الأولي (Prototype)](/design-patterns/prototype) لتركيب الدوال على هذه الفئات.
* يمكن أن يعمل [المصنع المجرد (Abstract Factory)](/design-patterns/abstract-factory) كبديل لـ [الواجهة (Facade)](/design-patterns/facade) عندما تريد فقط إخفاء طريقة إنشاء كائنات النظام الفرعي عن كود العميل.
* يمكنك استخدام [المصنع المجرد (Abstract Factory)](/design-patterns/abstract-factory) مع [الجسر (Bridge)](/design-patterns/bridge). هذا الاقتران مفيد عندما لا تعمل بعض التجريدات التي يحددها _الجسر_ إلا مع تطبيقات محددة. في هذه الحالة، يمكن لـ _المصنع المجرد_ تغليف هذه العلاقات وإخفاء التعقيد عن كود العميل.
* يمكن تنفيذ كل من [المصانع المجردة](/design-patterns/abstract-factory) و [البناة](/design-patterns/builder) و [النماذج الأولية](/design-patterns/prototype) كـ [أحادية الحالة (Singletons)](/design-patterns/singleton).

## إضافات

* اقرأ [مقارنة المصانع](/design-patterns/factory-comparison) لمعرفة المزيد عن الاختلافات بين أنماط ومفاهيم المصانع المختلفة.
## Relations

**Related patterns**

- [طريقة المصنع](/ar/design-patterns/factory-method.md)
- [النموذج الأولي (Prototype)](/ar/design-patterns/prototype.md)
- [البنّاء](/ar/design-patterns/builder.md)
- [الواجهة (Facade)](/ar/design-patterns/facade.md)
- [الجسر](/ar/design-patterns/bridge.md)
- [Singleton](/ar/design-patterns/singleton.md)

## Code Examples

### java

```java
package refactoring_guru.abstract_factory.example.buttons;

/**
 * يفترض المصنع المجرد أن لديك عدة عائلات من المنتجات،
 * مرتبة في تدرجات هرمية منفصلة للفئات (Button/Checkbox). جميع منتجات
 * نفس العائلة لها واجهة مشتركة.
 *
 * هذه هي الواجهة المشتركة لعائلة الأزرار (buttons).
 */
public interface Button {
    void paint();
}

package refactoring_guru.abstract_factory.example.buttons;

/**
 * تمتلك جميع عائلات المنتجات نفس الأنواع (MacOS/Windows).
 *
 * هذا هو البديل الخاص بنظام MacOS للزر.
 */
public class MacOSButton implements Button {

    @Override
    public void paint() {
        System.out.println("You have created MacOSButton.");
    }
}

package refactoring_guru.abstract_factory.example.buttons;

/**
 * تمتلك جميع عائلات المنتجات نفس الأنواع (MacOS/Windows).
 *
 * هذا هو بديل آخر للزر.
 */
public class WindowsButton implements Button {

    @Override
    public void paint() {
        System.out.println("You have created WindowsButton.");
    }
}

package refactoring_guru.abstract_factory.example.checkboxes;

/**
 * خانات الاختيار (Checkboxes) هي عائلة المنتجات الثانية. ولها نفس بدائل الأزرار.
 */
public interface Checkbox {
    void paint();
}

package refactoring_guru.abstract_factory.example.checkboxes;

/**
 * تمتلك جميع عائلات المنتجات نفس الأنواع (MacOS/Windows).
 *
 * هذا هو بديل لخانة الاختيار (checkbox).
 */
public class MacOSCheckbox implements Checkbox {

    @Override
    public void paint() {
        System.out.println("You have created MacOSCheckbox.");
    }
}

package refactoring_guru.abstract_factory.example.checkboxes;

/**
 * تمتلك جميع عائلات المنتجات نفس الأنواع (MacOS/Windows).
 *
 * هذا بديل آخر لخانة الاختيار (checkbox).
 */
public class WindowsCheckbox implements Checkbox {

    @Override
    public void paint() {
        System.out.println("You have created WindowsCheckbox.");
    }
}

package refactoring_guru.abstract_factory.example.factories;

import refactoring_guru.abstract_factory.example.buttons.Button;
import refactoring_guru.abstract_factory.example.checkboxes.Checkbox;

/**
 * يعرف المصنع المجرد عن جميع أنواع المنتجات (المجردة).
 */
public interface GUIFactory {
    Button createButton();
    Checkbox createCheckbox();
}

package refactoring_guru.abstract_factory.example.factories;

import refactoring_guru.abstract_factory.example.buttons.Button;
import refactoring_guru.abstract_factory.example.buttons.MacOSButton;
import refactoring_guru.abstract_factory.example.checkboxes.Checkbox;
import refactoring_guru.abstract_factory.example.checkboxes.MacOSCheckbox;

/**
 * يوسع كل مصنع ملموس المصنع الأساسي وهو مسؤول عن إنشاء
 * منتجات من نوع واحد.
 */
public class MacOSFactory implements GUIFactory {

    @Override
    public Button createButton() {
        return new MacOSButton();
    }

    @Override
    public Checkbox createCheckbox() {
        return new MacOSCheckbox();
    }
}

package refactoring_guru.abstract_factory.example.factories;

import refactoring_guru.abstract_factory.example.buttons.Button;
import refactoring_guru.abstract_factory.example.buttons.WindowsButton;
import refactoring_guru.abstract_factory.example.checkboxes.Checkbox;
import refactoring_guru.abstract_factory.example.checkboxes.WindowsCheckbox;

/**
 * يوسع كل مصنع ملموس المصنع الأساسي وهو مسؤول عن إنشاء
 * منتجات من نوع واحد.
 */
public class WindowsFactory implements GUIFactory {

    @Override
    public Button createButton() {
        return new WindowsButton();
    }

    @Override
    public Checkbox createCheckbox() {
        return new WindowsCheckbox();
    }
}

package refactoring_guru.abstract_factory.example.app;

import refactoring_guru.abstract_factory.example.buttons.Button;
import refactoring_guru.abstract_factory.example.checkboxes.Checkbox;
import refactoring_guru.abstract_factory.example.factories.GUIFactory;

/**
 * لا يهتم مستخدمو المصنع بالمصنع الملموس الذي يستخدمونه لأنهم يعملون مع
 * المصانع والمنتجات من خلال واجهات مجردة.
 */
public class Application {
    private Button button;
    private Checkbox checkbox;

    public Application(GUIFactory factory) {
        button = factory.createButton();
        checkbox = factory.createCheckbox();
    }

    public void paint() {
        button.paint();
        checkbox.paint();
    }
}

package refactoring_guru.abstract_factory.example;

import refactoring_guru.abstract_factory.example.app.Application;
import refactoring_guru.abstract_factory.example.factories.GUIFactory;
import refactoring_guru.abstract_factory.example.factories.MacOSFactory;
import refactoring_guru.abstract_factory.example.factories.WindowsFactory;

/**
 * فئة تجريبية (Demo class). كل شيء يجتمع معاً هنا.
 */
public class Demo {

    /**
     * يختار التطبيق نوع المصنع وينشئه في وقت التشغيل (عادةً في مرحلة
     * التهيئة)، اعتماداً على التكوين أو متغيرات البيئة.
     */
    private static Application configureApplication() {
        Application app;
        GUIFactory factory;
        String osName = System.getProperty("os.name").toLowerCase();
        if (osName.contains("mac")) {
            factory = new MacOSFactory();
        } else {
            factory = new WindowsFactory();
        }
        app = new Application(factory);
        return app;
    }

    public static void main(String[] args) {
        Application app = configureApplication();
        app.paint();
    }
}

You create WindowsButton.
You created WindowsCheckbox.
```

