Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

الخصوصية على مستوى المكتبة

جزء من قسم 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) الموجودة في نفس الملف يمكنها التعاون بشكل وثيق مع الاستمرار في إخفاء تفاصيل التنفيذ عن الكود الخارجي. إنه خيار تصميمي متعمد يشجع على تنظيم الأصناف المرتبطة معاً في نفس المكتبة.

challenge icon

التحدي

سهل

لنقم ببناء نظام تعاون جماعي يوضح كيفية عمل الخصوصية على مستوى المكتبة (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
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming