UML: مخططات الفئات والكائنات

فئات الارتباط والاعتماديات

18 دقيقة الدرس 6 من 10

فئات الارتباط والاعتماديات

معظم الارتباطات في مخطط الفئات بسيطة: خط يصل بين فئتين مع تسميات التعددية. لكن ماذا يحدث حين العلاقة ذاتها تحمل بيانات؟ وكيف تُظهر أن فئة ما تستخدم أخرى فحسب دون أن تمتلكها أو تعرفها بشكل دائم؟ يقدم هذا الدرس نوعين من التدوينات القوية والمهملة كثيراً: فئة الارتباط وسهم الاعتمادية.

حين تحمل العلاقة خصائص

لنتأمل نظام المواعيد في عيادة طبية. يمكن للمريض حجز مواعيد مع أطباء متعددين، ويمكن للطبيب خدمة مرضى متعددين. هذا ارتباط كثير-إلى-كثير مباشر. لكن الموعد نفسه يحمل بيانات خاصة: التاريخ والوقت وسبب الزيارة والحالة. أين تعيش هذه الخصائص؟

لا تنتمي طبيعياً إلى Patient (المريض ليس له تاريخ واحد — بل كل حجز له تاريخه)، ولا إلى Doctor أيضاً. إنها تنتمي إلى العلاقة بين المريض والطبيب في سياق حجز بعينه. يُعبّر UML عن هذا بـفئة الارتباط: مستطيل فئة متصل بخط الارتباط بواسطة خط متقطع، يضم الخصائص التي تصف الرابط نفسه.

قاعدة عملية: إذا وجدت نفسك تضيف خصائص مثل enrollmentDate أو discountRate إلى إحدى الفئتين المشاركتين، لكنها لا تعني شيئاً إلا في سياق الرابط، فأنت بحاجة إلى فئة ارتباط.
Association Class: Patient books Doctor via Appointment Patient - patientId: String - name: String - dateOfBirth: Date (operations) Doctor - doctorId: String - name: String - specialty: String (operations) 1..* 1..* books Appointment - date: Date - time: Time - reason: String - status: {Pending,Confirmed,Cancelled}
فئة الارتباط Appointment متصلة بالخط بين Patient وDoctor، وتحمل الخصائص التي لا توجد إلا في سياق حجز بعينه.

قراءة فئة الارتباط

يعني الخط المتقطع من مستطيل فئة الارتباط إلى خط الارتباط: "هذه الفئة تصف هذا الرابط." في التنفيذ، تتحول فئة الارتباط عادةً إلى جدول وصل في قاعدة بيانات علائقية (مثل جدول appointments مع مفاتيح أجنبية لكلا الجدولين) أو كيان مستقل في الكود.

مثال آخر من متجر إلكتروني: يمكن للعميل الانضمام إلى مستويات متعددة من برنامج الولاء، ويمكن للمستوى الواحد أن يضم عملاء متعددين. للاشتراك بياناته الخاصة: enrollmentDate وpointsEarned وtier. هذه تعيش في فئة ارتباط باسم Enrollment متصلة بارتباط Customer-to-LoyaltyProgram.

اتفاقية التسمية: تُسمى فئات الارتباط عادةً باسم الحدث أو الدور الذي يمثله الرابط — Appointment، Enrollment، Rental، OrderLine. الاسم الذي يصف فعل الربط بين الطرفين هو الدليل الأمثل.

أسهم الاعتمادية

يعرّف UML الاعتمادية بأنها علاقة يمكن فيها لأي تغيير في عنصر (المُورِّد) أن يؤثر على عنصر آخر (العميل). تُرسم بـسهم متقطع برأس مفتوح يشير من العميل نحو المُورِّد.

الاعتماديات أضعف وأكثر عابرية من الارتباطات. الارتباط يعني أن الكائن A يحتفظ بمرجع دائم للكائن B (حقل في تعريفه). الاعتمادية تعني فحسب أن الفئة تستخدم أخرى — ربما كمعامل لدالة، أو متغير محلي، أو استدعاء لأداة مساعدة. العميل لا يعرف المُورِّد بشكل دائم؛ يحتاجه لحظة واحدة فقط.

سيناريوهات شائعة لأسهم الاعتمادية في نظام عيادة أو مكتبة:

  • خدمة BookingService تنشئ كائن EmailNotification مؤقتاً لإرسال تأكيد — لا تخزنه بشكل دائم.
  • فئة InvoiceReport تستدعي أداة TaxCalculator بالمبالغ وتستلم النتائج — التقرير لا يمتلك الحاسبة.
  • فئة PatientController (طبقة الويب) تعتمد على واجهة PatientRepository دون الإشارة الدائمة إلى تنفيذات بعينها.
Dependency Arrows in a Booking System BookingService + createAppointment() + cancelAppointment() EmailNotification + send(to, subject, body) - template: String TaxCalculator + calculate(amount): Decimal + vatRate(): Decimal InvoiceReport + generate(bookingId) + exportPdf() EmailNotification --> «use» TaxCalculator --> «use» InvoiceReport --> «use»
تُظهر الأسهم المتقطعة المفتوحة أن BookingService تستخدم EmailNotification وInvoiceReport بصورة عابرة، وأن InvoiceReport تستخدم TaxCalculator كأداة مساعدة — لا توجد علاقات ملكية دائمة بينها.

الفرق بين الارتباط والاعتمادية

الفارق يكمن في الديمومة والملكية:

  • الارتباط (خط متصل): الكائن A يحتفظ بمرجع للكائن B في حقل دائم. لو طبعت حالة A لرأيت B مُدرجاً فيها. أمثلة: Order له Customer؛ Doctor له قائمة من كائنات Appointment.
  • الاعتمادية (سهم متقطع): الكائن A لا يعرف B إلا أثناء استدعاء دالة — كمعامل أو متغير محلي أو قيمة مُعادة. حين تنتهي الدالة يختفي الرابط. أمثلة: ReportGenerator يستقبل DateRange كمعامل؛ Controller ينشئ Validator مؤقتاً ثم يتخلى عنه.
كثرة الاعتماديات نذير تصميم سيء: إذا رسمت أسهم اعتمادية تخرج من فئة واحدة نحو فئات كثيرة، فتلك الفئة تتحمل مسؤوليات أكثر مما ينبغي — وهو انتهاك لمبدأ المسؤولية الواحدة. النظام المُصمَّم جيداً له اعتماديات قليلة وضيقة. احسب أسهم الاعتمادية الخارجة من كل فئة أثناء مراجعة التصميم؛ أربعة أو خمسة أو أكثر إشارة تحذير.

النمطيات على أسهم الاعتمادية

يتيح UML تسمية الاعتمادية بـنمطية بين شولتين لتوضيح طبيعتها. أبرز ما يستخدمه المحللون والمهندسون:

  • «use» — الفئة العميلة تستدعي دوال المُورِّد (الافتراض الضمني).
  • «create» — الفئة العميلة تُنشئ كائنات من الفئة المُورِّدة.
  • «call» — الفئة العميلة تستدعي دالة محددة في المُورِّد.
  • «instantiate» — كـcreate لكنها تُبرز نمط المصنع.

في الواقع العملي، تكتفي معظم المخططات على مستوى تحليل الأعمال بالسهم المتقطع بلا نمطية مع الاتكاء على السياق. تصبح النمطيات مهمة حين يستلم المهندسون والمطورون المخطط ويحتاجون معرفة الآلية الدقيقة.

سير عمل عملي: اكتشاف فئات الارتباط

  1. حدد كل ارتباط كثير-إلى-كثير في مسودة مخطط الفئات.
  2. اسأل: "هل يحمل هذا الرابط بيانات خاصة، أو هل له دورة حياة مستقلة (يُنشأ ويُعدَّل ويُؤرشَف)؟"
  3. إذا كانت الإجابة نعم — ارقِ الرابط إلى فئة ارتباط وسمِّها.
  4. اسأل أصحاب المصلحة: "ما المعلومات التي تسجلونها عن هذا الحدث الرابط؟" ستملأ إجاباتهم خصائص فئة الارتباط.

في نظام مكتبة: Member يستعير نسخاً كثيرة من Book، والنسخة الواحدة يمكن استعارتها من أعضاء متعددين عبر الزمن. لرابط الاستعارة borrowDate وdueDate وreturnDate وfineAmount. هذه هي فئة الارتباط Loan.

خلاصة

  • فئة الارتباط هي مستطيل فئة متصل بخط الارتباط عبر خط متقطع؛ تحمل خصائص وعمليات تنتمي للعلاقة لا لأي من الفئتين المشاركتين.
  • تنشأ فئات الارتباط عادةً من ارتباطات كثير-إلى-كثير حين يكون للرابط بيانات خاصة — حجوزات، اشتراكات، إعارات، بنود طلبات.
  • الاعتمادية سهم متقطع برأس مفتوح يُظهر أن فئة تستخدم أخرى بصورة عابرة — كمعامل دالة أو متغير محلي أو استدعاء أداة مساعدة — دون الاحتفاظ بمرجع دائم.
  • الارتباط = ملكية دائمة (حقل). الاعتمادية = استخدام لحظي (نطاق الدالة).
  • النمطيات («use»، «create») على أسهم الاعتمادية تُضيف دقة حين تكون ضرورية.