التحقق من البيانات في الـ Setters
جزء من قسم البرمجة كائنية التوجه في رحلة C على Coddy. الدرس 20 من 61.
في الدرس السابق، أنشأنا دوالّ ضبط أساسية لا تفعل سوى إسناد القيم. لكن هذا يُفوّت فائدة أساسية من فوائد التغليف: القدرة على حماية بياناتك من خلال إضافة منطق للتحقق من الصحة.
تخيّل Counter الذي يجب ألا تصبح قيمته سالبة أبدًا. من دون التغليف، يمكن لأي شخص كتابة c->value = -50 وإفساد الحالة. باستخدام دالة ضبط، يمكنك التحكم في القيم المسموح بها:
// counter.c
void counter_set_value(Counter *c, int new_value) {
if (new_value < 0) {
return; // ارفض المدخلات غير الصالحة بصمت
}
c->value = new_value;
}الآن يتم تجاهل القيم السالبة ببساطة.
قد تختار أيضًا إرجاع رمز حالة للإشارة إلى النجاح أو الفشل:
int counter_set_value(Counter *c, int new_value) {
if (new_value < 0) {
return 0; // فشل
}
c->value = new_value;
return 1; // نجاح
}يتيح هذا النمط للجهة المستدعية معرفة ما إذا كانت العملية قد نجحت. والفكرة الأساسية هي أن دوال الضبط لا تقتصر على الإسناد، بل إنها حراس يفرضون قواعد بشأن الحالات التي يمكن أن يكون عليها كائنك. وهذه هي القوة الحقيقية للتغليف: يحافظ كائنك على سلامته، بصرف النظر عما تحاول الشيفرة الخارجية فعله.
التحدي
سهللننشئ وحدة Temperature تحمي بياناتها باستخدام التحقق في دالة الضبط. ستنشئ متعقّبًا لدرجة الحرارة لا يقبل إلا القيم ضمن نطاق صالح، موضحًا كيف تعمل دوال الضبط كحراس لحالة الكائن.
ستنشئ ثلاثة ملفات:
temperature.h: واجهتك العامة باستخدام نمط المؤشر المعتم. صرّح عن النوعTemperatureباستخدام تصريح أمامي فقط. صرّح عن هذه الدوال:create_temperature: تأخذ عددًا صحيحًا لدرجة الحرارة الابتدائية وتُعيد مؤشرًا إلى Temperaturefree_temperature: تحرر الذاكرة المخصصةtemp_get_degrees: دالة جلب تُعيد قيمة درجة الحرارة الحاليةtemp_set_degrees: دالة ضبط تُعيدint(1 للنجاح، و0 للإخفاق)
TEMPERATURE_H.temperature.c: عرّف البنية الفعليةstruct Temperatureمع عضو مخفيint degrees. نفّذ جميع الدوال. النقطة الأساسية هي دالة الضبط. يجب ألا تقبل إلا القيم بين -50 و150 (شاملًا). إذا كانت القيمة خارج هذا النطاق، فأعِد 0 واترك درجة الحرارة دون تغيير. وإذا كانت صالحة، فحدّث القيمة وأعِد 1.main.c: وضّح التحقق بمحاولة ضبط درجتي حرارة صالحة وغير صالحة، مع إظهار رفض القيم غير الصالحة وقبول القيم الصالحة.
ستتلقى ثلاث قيم إدخال: درجة الحرارة الابتدائية، ودرجة حرارة صالحة لضبطها (ضمن النطاق)، ودرجة حرارة غير صالحة لمحاولة ضبطها (خارج النطاق).
في ملفك الرئيسي، أنشئ Temperature بالقيمة الابتدائية واطبعها. ثم حاول ضبط درجة الحرارة غير الصالحة، وبما أنه يجب رفضها، اطبع النتيجة وأظهر أن القيمة بقيت دون تغيير. أخيرًا، اضبط درجة الحرارة الصالحة، واطبع نتيجة النجاح، وأظهر القيمة المحدّثة. حرر الذاكرة وأكّد إتمام التنظيف.
اطبع المخرجات بهذا التنسيق:
Initial: {degrees}
Set {invalid}: {0 or 1}
After invalid: {degrees}
Set {valid}: {0 or 1}
After valid: {degrees}
Freedعلى سبيل المثال، مع قيم الإدخال 25 و100 و200، ستكون المخرجات:
Initial: 25
Set 200: 0
After invalid: 25
Set 100: 1
After valid: 100
Freedيوضح هذا القوة الحقيقية للتغليف. تفرض دالة الضبط القواعد التي تحدد ما يُعد درجة حرارة صالحة، فتحمي سلامة الكائن بغض النظر عن القيم التي تحاول الشيفرة الخارجية تعيينها.
جرّب بنفسك
#include <stdio.h>
#include "temperature.h"
int main() {
// اقرأ المدخلات
int initial, valid_temp, invalid_temp;
scanf("%d", &initial);
scanf("%d", &valid_temp);
scanf("%d", &invalid_temp);
// TODO: أنشئ Temperature بالقيمة الأولية
// TODO: اطبع درجة الحرارة الأولية
// التنسيق: "Initial: {degrees}"
// TODO: حاول تعيين درجة الحرارة غير الصالحة
// اطبع النتيجة وأظهر أن القيمة لم تتغير
// التنسيق: "Set {invalid}: {0 or 1}"
// التنسيق: "After invalid: {degrees}"
// TODO: عيّن درجة الحرارة الصالحة
// اطبع نتيجة النجاح وأظهر القيمة المحدّثة
// التنسيق: "Set {valid}: {0 or 1}"
// التنسيق: "After valid: {degrees}"
// TODO: حرّر الذاكرة واطبع "Freed"
return 0;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
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مشروع: رسّام الأشكال
نظرة عامة على المشروعتنفيذ الدائرةتنفيذ المستطيلاستخدام تعدد الأشكالحاوية الأشكالتدرّب بنفسك: مترجم C عبر الإنترنت