نمط المنشئ (Constructor Pattern)
جزء من قسم Object Oriented Programming في رحلة C على Coddy — الدرس 12 من 61.
في لغات مثل Java أو C++، تقوم بإنشاء الكائنات باستخدام المنشئات (constructors)—وهي دوال خاصة تقوم بتخصيص الذاكرة وتهيئة الحقول تلقائيًا. لغة C لا تملك مثل هذه الميزة، ولكن يمكننا محاكاتها بنمط بسيط: دالة create_.
عادةً ما تقوم دالة المنشئ (constructor function) في لغة C بثلاثة أشياء: تخصيص الذاكرة باستخدام malloc، وتهيئة جميع الحقول بالقيم المناسبة، وإرجاع مؤشر (pointer) إلى الكائن الجديد:
typedef struct {
char *name;
int age;
} Person;
Person *create_person(const char *name, int age) {
Person *p = malloc(sizeof(Person));
p->name = malloc(strlen(name) + 1);
strcpy(p->name, name);
p->age = age;
return p;
}
تُعيد الدالة مؤشرًا لأن الكائن يتواجد في الـ heap، وليس في الـ stack. وهذا يعني أنه يستمر في الوجود بعد انتهاء تنفيذ الدالة ويمكن تمريره بحرية. يستخدمه المستدعي بهذا الشكل:
Person *alice = create_person("Alice", 30);
printf("%s is %d years old\n", alice->name, alice->age);
لاحظ كيف يتعامل الـ constructor مع جميع التفاصيل المعقدة—تخصيص الـ struct، وتخصيص مساحة للـ string، ونسخ البيانات. يقوم المستدعي (caller) فقط بتوفير القيم الأولية ويتلقى كائناً جاهزاً للاستخدام. هذا يغلف منطق الإنشاء في مكان واحد، مما يجعل الكود الخاص بك أكثر نظافة وأقل عرضة للأخطاء.
التحدي
سهللنقم ببناء وحدة Book تستخدم نمط المنشئ (constructor pattern) لإنشاء كائنات كتاب في الذاكرة الحيوية (heap). ستتدرب على كتابة دالة create_ تتولى جميع عمليات تخصيص الذاكرة والتهيئة، وتعيد مؤشراً جاهزاً للاستخدام.
ستقوم بإنشاء ثلاثة ملفات:
book.h: قم بالتصريح عن هيكلBookيحتوي على عضوين:char *title(مؤشر إلى سلسلة نصية مخصصة ديناميكياً) وint pages. قم أيضاً بالتصريح عن دالة المنشئcreate_bookالتي تأخذ سلسلة نصية للعنوان وعدد الصفحات، ثم تعيد مؤشراً إلى Book تم إنشاؤه حديثاً. استخدم حراس التضمين (include guards) مع الرمزBOOK_H.book.c: قم بتنفيذ دالةcreate_book. يجب أن يقوم المنشئ الخاص بك بتخصيص ذاكرة لهيكل Book نفسه، ثم تخصيص ذاكرة منفصلة لسلسلة العنوان (تذكر حساب حرف النهاية الصفري null terminator)، ونسخ العنوان إلى الذاكرة الجديدة، وتعيين حقل الصفحات، وإعادة المؤشر إلى Book الجديد.main.c: استخدم المنشئ الخاص بك لإنشاء كتاب وعرض معلوماته.
ستتلقى مدخلين: عنوان الكتاب (سلسلة نصية) و عدد الصفحات (عدد صحيح).
في ملفك الرئيسي، استخدم create_book لإنشاء كتاب جديد بالقيم المقدمة، ثم اطبع معلوماته بهذا التنسيق:
Title: {title}
Pages: {pages}على سبيل المثال، مع المدخلات The C Programming Language و 272، سيكون الناتج:
Title: The C Programming Language
Pages: 272تذكر أن المنشئ الخاص بك يغلف كل منطق الإنشاء — حيث يقوم المستدعي ببساطة بتقديم القيم الأولية ويتلقى كائناً مهيأً بالكامل وجاهزاً للاستخدام.
ورقة مرجعية
تحاكي دالة المنشئ (constructor function) في لغة C عملية إنشاء الكائنات من خلال تخصيص الذاكرة وتهيئة الحقول. وعادةً ما تتبع نمط التسمية create_.
تقوم دالة المنشئ بثلاثة أشياء:
- تخصيص الذاكرة باستخدام
malloc - تهيئة جميع الحقول بالقيم المناسبة
- إرجاع مؤشر (pointer) إلى الكائن الجديد
مثال على نمط المنشئ:
typedef struct {
char *name;
int age;
} Person;
Person *create_person(const char *name, int age) {
Person *p = malloc(sizeof(Person));
p->name = malloc(strlen(name) + 1);
strcpy(p->name, name);
p->age = age;
return p;
}
استخدام المنشئ:
Person *alice = create_person("Alice", 30);
printf("%s is %d years old\n", alice->name, alice->age);
تعيد الدالة مؤشراً لأن الكائن يعيش في الذاكرة الحرة (heap) ويستمر وجوده بعد انتهاء تنفيذ الدالة. هذا يغلف منطق الإنشاء في مكان واحد، مما يجعل الكود أكثر نظافة وأقل عرضة للأخطاء.
جرّب بنفسك
#include <stdio.h>
#include <stdlib.h>
#include "book.h"
int main() {
char title[256];
int pages;
// قراءة المدخلات
fgets(title, sizeof(title), stdin);
// إزالة سطر جديد إذا كان موجوداً
for (int i = 0; title[i]; i++) {
if (title[i] == '\n') {
title[i] = '\0';
break;
}
}
scanf("%d", &pages);
// TODO: استخدم create_book لإنشاء كتاب جديد بالقيم المقدمة
// TODO: اطبع معلومات الكتاب بالتنسيق المطلوب:
// Title: {title}
// Pages: {pages}
// 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مشروع: رسّام الأشكال
نظرة عامة على المشروعتنفيذ الدائرة