تنفيذ الـ Interfaces
جزء من قسم البرمجة كائنية التوجه في رحلة C على Coddy. الدرس 41 من 61.
الآن بعد أن فهمت ما هي الواجهة، وهي بنية تحتوي على مؤشرات دوال فقط، حان الوقت لإنشاء تطبيقات ملموسة تفي بهذا العقد.
تذكّر واجهة ILogger من الدرس السابق:
typedef void (*LogFunc)(const char* message);
typedef struct {
LogFunc log;
} ILogger;لتنفيذ هذه الواجهة، نكتب دوال فعلية تطابق توقيع LogFunc، ثم ننشئ مثيلات من ILogger مع تعيين تلك الدوال لها:
void console_log(const char* message) {
printf("[CONSOLE] %s\n", message);
}
void file_log(const char* message) {
printf("[FILE] %s\n", message); // محاكاة إخراج الملف
}
ILogger create_console_logger() {
ILogger logger = { console_log };
return logger;
}
ILogger create_file_logger() {
ILogger logger = { file_log };
return logger;
}تُرجع كل دالة "constructor" ILogger مع ربط function مختلفة بها. لا يحتاج الكود الذي يستخدم أدوات التسجيل هذه إلى معرفة أي تنفيذ تلقّاه:
void do_work(ILogger* logger) {
logger->log("Starting work...");
logger->log("Work complete!");
}
int main() {
ILogger console = create_console_logger();
ILogger file = create_file_logger();
do_work(&console); // يستخدم console_log
do_work(&file); // يستخدم file_log
return 0;
}الدالة do_work منفصلة تمامًا عن تنفيذ التسجيل. يمكنك تبديل أدوات التسجيل بحرية دون تغيير أي من المنطق الأساسي: تلك هي قوة البرمجة وفق واجهة.
التحدي
سهللنبنِ نظام INotifier يوضّح كيف يمكن لتطبيقات مختلفة تلبية عقد الواجهة نفسه. ستنشئ مُرسِلَي إشعارات ملموسين، EmailNotifier وSMSNotifier، يلتزمان كلاهما بواجهة مشتركة لكنهما ينتجان مخرجات مختلفة.
ستنظّم شفرتك عبر ثلاثة ملفات:
notifier.h: عرّف الواجهة هنا. أنشئ نوع مؤشر دالة يُسمّىNotifyFuncويأخذ رسالة من نوعconst char*ولا يعيد أي قيمة. ثم عرّف بنيةINotifierالتي تحتوي فقط على مؤشر دالةnotifyمن هذا النوع. أعلن أيضًا عن دالتي constructor:create_email_notifierوcreate_sms_notifier، بحيث تعيد كل منهما قيمة من نوعINotifier.notifier.c: نفّذ دوال الإشعارات الملموسة وconstructor هنا. أنشئ:email_notify: تطبع الرسالة بالتنسيق:[EMAIL] messagesms_notify: تطبع الرسالة بالتنسيق:[SMS] messagecreate_email_notifier: تعيد قيمةINotifierموصولة بـemail_notifycreate_sms_notifier: تعيد قيمةINotifierموصولة بـsms_notify
main.c: اجمع كل شيء هنا. اقرأ نوع الإشعار ورسالة، وأنشئ مُرسِل الإشعارات المناسب باستخدام دوال constructor، ثم أرسل الإشعار من خلال الواجهة.
سيستقبل برنامجك مُدخلين: نوع الإشعار (1 للبريد الإلكتروني، و2 للرسائل النصية SMS) ورسالة لإرسالها.
استخدم دوال constructor لإنشاء مُرسِل الإشعارات المناسب، ثم استدعِ notify من خلال الواجهة لعرض الرسالة.
مثال على المخرجات عندما يكون النوع 1 والرسالة Meeting at 3pm:
[EMAIL] Meeting at 3pmمثال على المخرجات عندما يكون النوع 2 والرسالة Your code shipped:
[SMS] Your code shippedتكمن قوة هذا النمط في أن main.c لا يحتاج إلى معرفة كيفية عمل كل مُرسِل إشعارات داخليًا. فهو يستدعي ببساطة دالة الواجهة notify، ثم يُنفَّذ التطبيق الصحيح. تذكّر استخدام حواجز include في ملف الرأس.
جرّب بنفسك
#include <stdio.h>
#include "notifier.h"
int main() {
int type;
char message[256];
// اقرأ نوع الإشعار (1 للبريد الإلكتروني، 2 للرسائل القصيرة)
scanf("%d", &type);
getchar(); // استهلك السطر الجديد
// اقرأ الرسالة
fgets(message, sizeof(message), stdin);
// أزل السطر الجديد اللاحق إن وُجد
int len = 0;
while (message[len] != '\0') len++;
if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
// TODO: أنشئ المُبلِّغ المناسب بناءً على النوع
// استخدم create_email_notifier() للنوع 1
// استخدم create_sms_notifier() للنوع 2
// TODO: استدعِ دالة notify عبر الواجهة
// notifier.notify(message);
return 0;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات البرمجة التركيبية
ملفات الترويسةحواجز التضمينملفات المصدرالدوال الساكنةمراجعة: آلة حاسبة تركيبية4التغليف (Encapsulation)
مفهوم الـ Opaque Pointersتعريف الـ Opaque Structsالـ Getters والـ Settersالتحقق من البيانات في الـ Settersملخص: الصندوق السري2الكائنات والأساليب
الـ Structs ككائناتمؤشر 'Self'صحة استخدام Constالمؤشر مقابل القيمةالأساليب المساعدةملخص: Point Manager5مشروع: حساب بنكي بسيط
إعداد المشروعتنفيذ الحساب8تعدد الأشكال (Polymorphism)
مؤشرات الدوال في الـ Structsمحاكاة الـ Methodsمفهوم الـ Interfaceتنفيذ الـ Interfacesالتكرار متعدد الأشكالمراجعة: Greeter3دورة حياة الكائن
نمط المنشئ (Constructor Pattern)نمط الهادم (Destructor Pattern)تهيئة الـ Stackالنسخ العميق (Deep Copy)مراجعة: String Wrapper6الوراثة عبر التركيب
تضمين الـ Structقاعدة العضو الأولالوصول إلى أعضاء الأبعملية الـ Upcastingمراجعة: هرمية الأشكال9مشروع: رسّام الأشكال
نظرة عامة على المشروعتنفيذ الدائرةتنفيذ المستطيلاستخدام تعدد الأشكالحاوية الأشكالتدرّب بنفسك: مترجم C عبر الإنترنت