Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

نمط Factory و Abstract Factory

جزء من قسم البرمجة كائنية التوجه في رحلة C++ على Coddy. الدرس 92 من 104.

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

يستخدم المصنع البسيط أسلوبًا يُرجع أنواعًا مشتقة مختلفة استنادًا إلى الإدخال:

#include <iostream>
#include <memory>

class Button {
public:
    virtual void render() = 0;
    virtual ~Button() = default;
};

class WindowsButton : public Button {
public:
    void render() override { std::cout << "Windows button\n"; }
};

class MacButton : public Button {
public:
    void render() override { std::cout << "Mac button\n"; }
};

// دالة المصنع
std::unique_ptr<Button> createButton(const std::string& os) {
    if (os == "windows") return std::make_unique<WindowsButton>();
    if (os == "mac") return std::make_unique<MacButton>();
    return nullptr;
}

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

class Checkbox {
public:
    virtual void check() = 0;
    virtual ~Checkbox() = default;
};

class WindowsCheckbox : public Checkbox {
public:
    void check() override { std::cout << "Windows checkbox\n"; }
};

class MacCheckbox : public Checkbox {
public:
    void check() override { std::cout << "Mac checkbox\n"; }
};

// المصنع التجريدي
class GUIFactory {
public:
    virtual std::unique_ptr<Button> createButton() = 0;
    virtual std::unique_ptr<Checkbox> createCheckbox() = 0;
    virtual ~GUIFactory() = default;
};

class WindowsFactory : public GUIFactory {
public:
    std::unique_ptr<Button> createButton() override {
        return std::make_unique<WindowsButton>();
    }
    std::unique_ptr<Checkbox> createCheckbox() override {
        return std::make_unique<WindowsCheckbox>();
    }
};

استخدم Factory عندما تحتاج إلى إنشاء كائنات بمرونة، واستخدم Abstract Factory عندما تحتاج إلى ضمان عمل الكائنات المرتبطة معًا بصورة متسقة.

challenge icon

التحدي

سهل

لنَبْنِ نظام Document Generator باستخدام نمطي Factory وAbstract Factory. ستنشئ نظامًا يمكنه إنشاء أنواع مختلفة من المستندات (التقارير والفواتير) بتنسيقات إخراج مختلفة (PDF وHTML)، موضحًا كيف تفصل المصانع إنشاء الكائنات عن كود العميل.

ستنظّم الكود عبر أربعة ملفات:

  • Document.h: عرّف تسلسل هرمي لمنتجات المستندات.

    أنشئ فئة أساسية abstract Document مع طريقة افتراضية محضة generate() تُرجع سلسلة تصف المستند المُنشأ، ومُدمّر افتراضي.

    ثم أنشئ أربع فئات مستندات concrete:

    • PDFReport: تُرجع generate() القيمة "Generating PDF Report"
    • HTMLReport: تُرجع generate() القيمة "Generating HTML Report"
    • PDFInvoice: تُرجع generate() القيمة "Generating PDF Invoice"
    • HTMLInvoice: تُرجع generate() القيمة "Generating HTML Invoice"
  • DocumentFactory.h: نفّذ كلًا من دالة مصنع بسيطة ومصنع abstract.

    أولًا، أنشئ دالة مصنع بسيطة تُسمى createDocument وتأخذ سلسلتين: نوع مستند ("report" أو "invoice") وتنسيقًا ("pdf" أو "html"). يجب أن تُرجع std::unique_ptr<Document> يشير إلى المستند concrete المناسب. أعد nullptr للتوليفات غير الصالحة.

    ثم أنشئ فئة مصنع abstract تُسمى DocumentFactory مع طريقتين افتراضيتين محضتين:

    • createReport(): تُرجع std::unique_ptr<Document>
    • createInvoice(): تُرجع std::unique_ptr<Document>

    نفّذ مصنعين concrete:

    • PDFFactory: ينشئ PDFReport وPDFInvoice
    • HTMLFactory: ينشئ HTMLReport وHTMLInvoice
  • DocumentService.h: أنشئ خدمة تستخدم المصنع abstract.

    عرّف فئة DocumentService تأخذ std::unique_ptr<DocumentFactory> في مُنشئها. يجب أن تحتوي على طريقة تُسمى generateAllDocuments() تستخدم المصنع لإنشاء تقرير وفاتورة، ثم تطبع نتيجة استدعاء generate() على كل منهما، كل نتيجة في سطر.

  • main.cpp: وضّح طريقتَي المصنع كلتيهما.

    اقرأ مدخلين:

    1. نوع مستند (report أو invoice)
    2. تنسيق (pdf أو html)

    أولًا، استخدم دالة المصنع البسيطة لإنشاء مستند استنادًا إلى المدخلات. اطبع نتيجة استدعاء generate() عليه.

    ثم اطبع سطرًا فارغًا.

    بعد ذلك، أنشئ DocumentService باستخدام المصنع appropriate استنادًا إلى مدخل التنسيق (استخدم PDFFactory مع pdf، وHTMLFactory مع html). استدعِ generateAllDocuments() لتوضيح كيف ينشئ المصنع abstract عائلة من المستندات المرتبطة.

على سبيل المثال، مع المدخلين report وpdf:

Generating PDF Report

Generating PDF Report
Generating PDF Invoice

ومع المدخلين invoice وhtml:

Generating HTML Invoice

Generating HTML Report
Generating HTML Invoice

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

جرّب بنفسك

#include <iostream>
#include <string>
#include <memory>
#include "Document.h"
#include "DocumentFactory.h"
#include "DocumentService.h"

using namespace std;

int main() {
    // اقرأ المدخلات
    string documentType;
    string format;
    cin >> documentType;
    cin >> format;
    
    // TODO: استخدم دالة المصنع البسيطة لإنشاء مستند
    // بناءً على مدخلات documentType و format
    // اطبع نتيجة استدعاء generate() عليه
    
    // اطبع سطراً فارغاً
    cout << endl;
    
    // TODO: أنشئ DocumentService مع المصنع المناسب
    // بناءً على مدخل format (PDFFactory لـ "pdf"، HTMLFactory لـ "html")
    // استدعِ generateAllDocuments() لتوضيح المصنع المجرد
    
    return 0;
}
quiz iconاختبر نفسك

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

جميع دروس البرمجة كائنية التوجه

13أنماط التصميم - الجزء الأول

مقدمة في أنماط التصميمنمط Singletonنمط Factory و Abstract Factoryنمط Builderنمط Observerنمط Strategy

تدرّب بنفسك: مترجم C++ عبر الإنترنت