الخصوصية على مستوى المكتبة
جزء من قسم Object Oriented Programming في رحلة Dart على Coddy — الدرس 32 من 110.
في لغة Dart، يتم فرض الخصوصية على مستوى المكتبة، وليس على مستوى الفئة (class). هذا تمييز أساسي عن لغات مثل Java أو ++C. المكتبة في Dart هي عادةً ملف واحد، أو ملفات متعددة متصلة بتوجيهات part.
الأعضاء الخاصون (الذين يبدأون بـ _) يمكن الوصول إليهم في أي مكان داخل نفس المكتبة، حتى من فئات أخرى:
// كلا الفئتين في نفس الملف (نفس المكتبة)
class Engine {
int _horsepower = 200; // خاص بهذه المكتبة
}
class Car {
void showPower(Engine engine) {
print(engine._horsepower); // يمكن الوصول إليه! نفس المكتبة
}
}ومع ذلك، عندما تستورد فئة (class) من ملف مختلف، تصبح أعضاؤها الخاصة مخفية حقًا:
// ملف: engine.dart
class Engine {
int _horsepower = 200;
int get power => _horsepower;
}
// ملف: main.dart
import 'engine.dart';
void main() {
var engine = Engine();
// print(engine._horsepower); // خطأ! لا يمكن الوصول إليه
print(engine.power); // يعمل - باستخدام الـ getter العام
}تعني هذه الخصوصية على مستوى المكتبة أن الأصناف (classes) الموجودة في نفس الملف يمكنها التعاون بشكل وثيق مع الاستمرار في إخفاء تفاصيل التنفيذ عن الكود الخارجي. إنه خيار تصميمي متعمد يشجع على تنظيم الأصناف المرتبطة معاً في نفس المكتبة.
التحدي
سهللنقم ببناء نظام تعاون جماعي يوضح كيفية عمل الخصوصية على مستوى المكتبة (library-level privacy) في Dart. ستتعرف على كيفية وصول الفئات (classes) الموجودة في نفس الملف إلى الأعضاء الخاصين (private members) لبعضها البعض، بينما لا يمكن للكود الموجود في ملفات منفصلة القيام بذلك.
ستقوم بتنظيم الكود الخاص بك في ملفين:
team.dart: سيحتوي هذا الملف على فئتين تعملان معاً بشكل وثيق في نفس المكتبة:- فئة
MemberمعString nameعام وint _performanceScoreخاص يتم تهيئته بـ50. قم بتضمين منشئ (constructor) يأخذ الاسم، و getter عام باسمperformanceScoreيعيد الدرجة الخاصة. - فئة
TeamLeadفي نفس الملف يمكنها الوصول إلى الحقل الخاص لـMemberمباشرة (لأنهما في نفس المكتبة). يجب أن تحتوي هذه الفئة علىString nameعام، ومنشئ يأخذ الاسم، وتابع (method) باسمevaluateMember(Member member)يصل مباشرة إلىmember._performanceScore، ويضيف10إليها، ويطبع[leadName] boosted [memberName]'s score to [newScore].
- فئة
main.dart: قم باستيراد ملف الفريق الخاص بك واستعرض الفرق في الوصول:- أنشئ
Memberباسم'Alice' - أنشئ
TeamLeadباسم'Bob' - اطبع
Initial score: [score]باستخدام الـ getter العام على Alice - اجعل Bob يقيم Alice باستخدام
evaluateMember - اطبع
Updated score: [score]باستخدام الـ getter العام - اطبع
Direct access from main: Not allowed(هذا يذكرنا بأنmain.dartلا يمكنه الوصول إلى_performanceScoreمباشرة لأنه في مكتبة مختلفة)
- أنشئ
الفكرة الأساسية هنا هي أن TeamLead يمكنه قراءة وتعديل _performanceScore الخاص بـ Member مباشرة لأن كلا الفئتين تعيشان في نفس الملف (نفس المكتبة). ومع ذلك، يجب أن يستخدم الكود في main.dart الـ getter العام لأنه في مكتبة مختلفة.
المخرجات المتوقعة:
Initial score: 50
Bob boosted Alice's score to 60
Updated score: 60
Direct access from main: Not allowedورقة مرجعية
في لغة Dart، يتم فرض الخصوصية على مستوى المكتبة، وليس على مستوى الفئة. المكتبة عادةً ما تكون ملفاً واحداً، أو ملفات متعددة مرتبطة بتوجيهات part.
تبدأ الأعضاء الخاصة بشرطة سفلية (_) ويمكن الوصول إليها في أي مكان داخل نفس المكتبة، حتى من الفئات الأخرى:
// كلتا الفئتين في نفس الملف (نفس المكتبة)
class Engine {
int _horsepower = 200; // خاص بهذه المكتبة
}
class Car {
void showPower(Engine engine) {
print(engine._horsepower); // يمكن الوصول إليه! نفس المكتبة
}
}عند استيراد فئة من ملف مختلف، تصبح أعضاؤها الخاصة مخفية:
// ملف: engine.dart
class Engine {
int _horsepower = 200;
int get power => _horsepower;
}
// ملف: main.dart
import 'engine.dart';
void main() {
var engine = Engine();
// print(engine._horsepower); // خطأ! لا يمكن الوصول إليه
print(engine.power); // يعمل - باستخدام getter عام
}يشجع هذا التصميم على تنظيم الفئات ذات الصلة معاً في نفس المكتبة، مما يسمح لها بالتعاون بشكل وثيق مع إخفاء تفاصيل التنفيذ عن الكود الخارجي.
جرّب بنفسك
import 'team.dart';
void main() {
// TODO: أنشئ Member باسم 'Alice'
// TODO: أنشئ TeamLead باسم 'Bob'
// TODO: اطبع "Initial score: [score]" باستخدام public getter الخاص بـ Alice
// TODO: اجعل Bob يقيم Alice باستخدام evaluateMember
// TODO: اطبع "Updated score: [score]" باستخدام public getter
// TODO: اطبع "Direct access from main: Not allowed"
// Note: لا يمكننا الوصول إلى alice._performanceScore هنا لأن
// main.dart موجود في مكتبة مختلفة عن team.dart
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات الـ OOP
الملفات الخارجيةالمكتبات والـ Importsمقدمة في الـ OOPالـ Classes مقابل الـ Objectsالكلمة المفتاحية thisالـ Methodsمتغيرات الـ Instanceأساسيات الـ Constructorمراجعة - آلة حاسبة بسيطة4أمان الـ Null
مقدمة في أمان الـ NullNullable مقابل Non-Nullableعاملا الـ ? و !الكلمة المفتاحية Late وأمان الـ Nullالعوامل المدركة للـ Nullأمان الـ Null في الـ Classesمراجعة - نظام ملف تعريف المستخدم7الفئات المجردة والواجهات
الفئات المجردةالدوال المجردةالواجهات في Dartالواجهات الضمنيةالتنفيذ مقابل التوسيعالواجهات المتعددةمراجعة - حاسبة الأشكال10المجموعات والأنماط العامة
نظرة عامة على List و Set و Mapالمجموعات آمنة النوعالفئات العامةالدوال العامةقيود الأنماط العامةIterable و Iteratorملخص - التخزين العام13مفاهيم OOP المتقدمة
التركيب مقابل الوراثة (Composition vs Inheritance)دوال التوسعة (Extension Methods)الأصناف القابلة للاستدعاء (Callable Classes)الأصناف المختومة (Sealed Classes - Dart 3)السجلات (Records - Dart 3)الأنماط والمطابقة (Patterns & Matching - 3.0)التعدادات مع الدوال (Enums with Methods)2المنشئات في Dart
المنشئ الافتراضيالمنشئات المسماةقوائم التهيئةالمنشئات الثابتةالمنشئات المصنعيةالمنشئات الموجهةملخص - بناء الأشكال5التغليف (Encapsulation)
الأعضاء العامة مقابل الخاصةاتفاقية البادئة _الخصوصية على مستوى المكتبةتعمق في Getters و Settersإخفاء المعلوماتمراجعة - سجلات الطلاب8Mixins
مقدمة إلى Mixinsإنشاء Mixinsاستخدام Mixins متعددةالكلمة المفتاحية on في MixinsMixin مقابل الوراثة (Inheritance)Mixin مقابل الواجهة (Interface)مراجعة - نظام الحيوانات (Animal System)3خصائص الـ Class
أعضاء الـ Instance مقابل الـ Staticحقول Final و Constمتغيرات Lateالـ Static Methods والحقولدوال الـ Getters والـ Settersمراجعة - مدير الحساب البنكي6الوراثة
أساسيات الوراثةالكلمة المفتاحية superإعادة تعريف الدوال (Method Overriding)الوسم @overrideالكلمة المفتاحية final Classالدوال البانية والوراثةمراجعة - هيكلية الموظفين9تعدد الأشكال
أساسيات تعدد الأشكالتعدد الأشكال عبر الـ Interfacesالتحقق من النوع أثناء التشغيلالمعاملات is و asالكلمة المفتاحية Covariantملخص - معالج الدفع12البرمجة الكائنية غير المتزامنة (Async OOP)
Futures و async/awaitأساسيات الـ Streamsمتحكمات الـ Streamsالـ Constructors غير المتزامنةالعمليات غير المتزامنة في دوال الكلاسمراجعة - جالب البيانات (Data Fetcher)15أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المستودع