نمط 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. سيبقى باقي الكود الخاص بك دون تغيير.
التحدي
سهللنقم ببناء 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!
create_pet— استخدم جملة switch علىPetTypeلاستدعاء المنشئ الصحيح وإرجاع النتيجة كـPet*. بالنسبة للأنواع غير الصالحة، أرجعNULL. قم بتنفيذfree_petلتحرير الذاكرة المخصصة.- الكلاب (Dogs) تطبع:
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;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات البرمجة التركيبية
ملفات الترويسةحواجز التضمينملفات المصدرالدوال الساكنةمراجعة: آلة حاسبة تركيبية4التغليف (Encapsulation)
مفهوم الـ Opaque Pointersتعريف الـ Opaque Structsالـ Getters والـ Settersالتحقق من البيانات في الـ Settersملخص: الصندوق السري2الكائنات والأساليب
الـ Structs ككائناتمؤشر 'Self'صحة استخدام Constالمؤشر مقابل القيمةالأساليب المساعدةملخص: Point Manager5مشروع: حساب بنكي بسيط
إعداد المشروعتنفيذ الحساب3دورة حياة الكائن
نمط المنشئ (Constructor Pattern)نمط الهادم (Destructor Pattern)تهيئة الـ Stackالنسخ العميق (Deep Copy)مراجعة: String Wrapper6الوراثة عبر التركيب
تضمين الـ Structقاعدة العضو الأولالوصول إلى أعضاء الأبعملية الـ Upcastingمراجعة: هرمية الأشكال9مشروع: رسّام الأشكال
نظرة عامة على المشروعتنفيذ الدائرة