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

نمط Factory

جزء من قسم Object Oriented Programming في رحلة C على Coddy — الدرس 55 من 61.

يقوم نمط المصنع (Factory pattern) بتركيز عملية إنشاء الكائنات في دالة واحدة. فبدلاً من توزيع malloc وكود التهيئة في جميع أنحاء برنامجك، يمكنك استدعاء دالة واحدة تقرر ما سيتم إنشاؤه وتعيد كائناً جاهزاً للاستخدام.

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

إليك تنفيذ نموذجي للمصنع:

typedef enum {
    SHAPE_CIRCLE,
    SHAPE_RECTANGLE
} ShapeType;

Shape* create_shape(ShapeType type) {
    switch (type) {
        case SHAPE_CIRCLE:
            return (Shape*)create_circle(5.0);
        case SHAPE_RECTANGLE:
            return (Shape*)create_rectangle(4.0, 3.0);
        default:
            return NULL;
    }
}

يأخذ المصنع معرفاً (عادةً ما يكون enum) ويستخدم جملة switch لتحديد أي منشئ (constructor) سيتم استدعاؤه. يقوم بإرجاع Shape* بغض النظر عن النوع الفعلي الذي تم إنشاؤه. لا يحتاج المستدعي إلى معرفة أي شيء عن Circle أو Rectangle — فهو يعمل ببساطة مع النوع الأساسي:

Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s);  // استدعاء متعدد الأشكال
free_shape(s);

هذا النمط يجعل إضافة أنواع جديدة أمراً سهلاً: فقط أضف قيمة enum جديدة وحالة case جديدة في الـ factory. سيبقى باقي الكود الخاص بك دون تغيير.

challenge icon

التحدي

سهل

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

ستقوم بتنظيم الكود الخاص بك عبر ثلاثة ملفات:

  • pet.h: قم بتعريف enum باسم PetType مع القيم PET_DOG، و PET_CAT، و PET_BIRD. أنشئ هيكل Pet أساسي يحتوي على مؤشر دالة لـ speak (والتي تأخذ const Pet* ولا تعيد شيئاً). صرّح عن دالة المصنع create_pet التي تأخذ PetType وتعيد Pet*، بالإضافة إلى دالة free_pet للتنظيف.
  • pet.c: قم بتعريف ثلاثة هياكل حيوانات أليفة ملموسة — Dog، و Cat، و Bird — بحيث يدمج كل منها Pet كعضو أول. قم بتنفيذ دالة speak لكل نوع:
    • الكلاب (Dogs) تطبع: Woof!
    • القطط (Cats) تطبع: Meow!
    • الطيور (Birds) تطبع: Tweet!
    أنشئ دوال بناء (constructor functions) لكل نوع من الحيوانات الأليفة تقوم بتخصيص الذاكرة وربط دالة speak المناسبة. ثم قم بتنفيذ مصنع create_pet — استخدم جملة switch على PetType لاستدعاء المنشئ الصحيح وإرجاع النتيجة كـ Pet*. بالنسبة للأنواع غير الصالحة، أرجع NULL. قم بتنفيذ free_pet لتحرير الذاكرة المخصصة.
  • main.c: اقرأ عدداً صحيحاً يمثل نوع الحيوان الأليف (0 للكلب، 1 للقط، 2 للطائر). استخدم المصنع الخاص بك لإنشاء الحيوان الأليف المناسب، واستدعِ دالة speak الخاصة به بشكل متعدد الأشكال (polymorphically) من خلال مؤشر Pet* الأساسي، ثم قم بتحرير الحيوان الأليف.

سيتلقى برنامجك مدخلاً واحداً: عدد صحيح يشير إلى الحيوان الأليف الذي سيتم إنشاؤه.

مثال على المخرجات عندما يكون الإدخال 0:

Woof!

مثال على المخرجات عندما يكون الإدخال 1:

Meow!

مثال على المخرجات عندما يكون الإدخال 2:

Tweet!

جمال نمط المصنع (Factory pattern) هو أن main.c لا يحتاج إلى معرفة هياكل Dog أو Cat أو Bird — فهو يعمل فقط مع النوع الأساسي Pet. إضافة نوع جديد من الحيوانات الأليفة لاحقاً يعني إضافة قيمة enum جديدة وحالة (case) جديدة في المصنع، دون تغيير أي كود يستخدم الحيوانات الأليفة.

ورقة مرجعية

يقوم نمط المصنع (Factory pattern) بتركيز عملية إنشاء الكائنات في دالة واحدة، مما يخفي تفاصيل الإنشاء عن المستدعي.

تأخذ دالة المصنع معرفاً (عادةً ما يكون enum) وتستخدم جملة switch لتحديد أي منشئ (constructor) سيتم استدعاؤه، وتعيد مؤشراً من النوع الأساسي (base type pointer):

typedef enum {
    SHAPE_CIRCLE,
    SHAPE_RECTANGLE
} ShapeType;

Shape* create_shape(ShapeType type) {
    switch (type) {
        case SHAPE_CIRCLE:
            return (Shape*)create_circle(5.0);
        case SHAPE_RECTANGLE:
            return (Shape*)create_rectangle(4.0, 3.0);
        default:
            return NULL;
    }
}

يعمل المستدعي فقط مع النوع الأساسي، مما يسمح بسلوك تعدد الأشكال (polymorphic behavior):

Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s);  // polymorphic call
free_shape(s);

الفوائد: إضافة أنواع جديدة تتطلب فقط إضافة قيمة enum جديدة وحالة switch جديدة، دون تغيير الكود الحالي الذي يستخدم المصنع.

جرّب بنفسك

#include <stdio.h>
#include "pet.h"

int main(void) {
    int type;
    scanf("%d", &type);
    
    // TODO: استخدم المصنع لإنشاء الحيوان الأليف المناسب
    // Hint: قم بتحويل الـ int إلى PetType
    
    // TODO: استدعِ الدالة speak بشكل متعدد الأشكال عبر المؤشر Pet*
    
    // TODO: قم بتحرير الحيوان الأليف
    
    return 0;
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming