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

العلاقات والتعددية في مخططات الفئات

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

العلاقات والتعددية في مخططات الفئات

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

ما هو الارتباط؟

الارتباط هو علاقة بنيوية تعني أن كائنات فئة ما مرتبطة بكائنات فئة أخرى بطريقة دائمة. في UML يُرسم الارتباط كخط صلب عادي بين مربعَي الفئتين. يمكنك إضافة:

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

قراءة تدوين التعددية

تُكتب التعددية كنطاق min..max بجانب طرف خط الارتباط، قرب الفئة التي تصفها. الأنماط الأربعة التي ستستخدمها باستمرار هي:

  • 1 — واحد بالضبط. يجب أن ينتمي الحجز إلى مريض واحد بالضبط.
  • 0..1 — صفر أو واحد (اختياري). قد يكون للموظف مكان انتظار معيّن أو لا يكون.
  • 1..* — واحد أو أكثر. يجب أن يكون للمقرر طالب مسجّل على الأقل.
  • * (اختصار لـ 0..*) — صفر أو أكثر. قد يكون للمؤلف كتب كثيرة أو لا يكون قد نشر بعد.
كيفية قراءة زوج التعددية: قف عند أحد طرفَي الخط واقرأ الرقم عند الطرف المقابل — فهو يخبرك بعدد نسخ تلك الفئة المرتبطة بنسخة واحدة من فئتك. الخط Patient–(1)—(*)–Appointment يعني: للمريض الواحد صفر أو أكثر من المواعيد، وكل موعد ينتمي إلى مريض واحد بالضبط.

المخطط الأول — نظام حجز عيادة

يُمثّل المخطط التالي عيادة طبية بسيطة. يحجز Patient (المريض) موعداً أو أكثر من Appointment (المواعيد). كل موعد يحضره Doctor (طبيب) واحد بالضبط. قد يُجري الطبيب مواعيد عدة لكن يجب أن يكون لديه واحد على الأقل (وإلا فهو ليس ممارساً). ادرس التعددية عند كل طرف من كل خط.

Clinic Booking Association Diagram Patient - patientId : String - name : String + bookAppointment() + getHistory() Appointment - appointmentId : String - date : Date + confirm() + cancel() + reschedule() Doctor - doctorId : String - specialty : String + getSchedule() + updateAvailability() 1 * places * 1 attended by دليل القراءة: Patient (1) ——places——> (*) Appointment : مريض واحد يملك صفراً أو أكثر من المواعيد Appointment (*) ——attended by——> (1) Doctor : كل موعد لديه طبيب واحد بالضبط
حجز العيادة: ارتباطات Patient وAppointment وDoctor مع علامات التعددية.

المخطط الثاني — المتجر الإلكتروني: الطلب وعناصره

يحتوي Order (الطلب) في المتجر الإلكتروني على عنصر OrderItem واحد أو أكثر (لا يمكن تقديم طلب فارغ). كل OrderItem يشير إلى Product واحد بالضبط. قد يظهر المنتج في عناصر طلبات كثيرة أو في لا شيء (منتج أُضيف حديثاً). يرتبط الطلب بـCustomer واحد بالضبط، الذي قد يكون لديه طلبات كثيرة أو لا شيء.

Online Store Order Class Diagram Customer - customerId : String - email : String + placeOrder() + viewHistory() Order - orderId : String - status : String + submit() + cancel() + calculateTotal() OrderItem - quantity : Integer - unitPrice : Decimal + getSubtotal() Product - productId : String - name, price 1 * places 1 1..* contains * 1 refers to
المتجر الإلكتروني: Customer وOrder وOrderItem وProduct مع تعددية دقيقة عند كل طرف ارتباط.

الارتباطات ثنائية الاتجاه وأحادية الاتجاه

بشكل افتراضي، خط الارتباط ثنائي الاتجاه — يمكن لكلا الكائنين التنقل إلى الآخر. يمكنك تقييد التنقل بإضافة رأس سهم مفتوح عند أحد الطرفين، مما يعني أن الفئة المصدر فقط هي التي تحتفظ بمرجع للفئة الهدف. العلامة × عند طرف تعني أن التنقل في ذلك الاتجاه محظور صراحةً.

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

الارتباط الذاتي (الانعكاسي)

يمكن أن ترتبط الفئة بنفسها. المثال الكلاسيكي هو Employee (الموظف) الذي قد يُشرف على موظفين آخرين: مدير واحد يُشرف على صفر أو أكثر من المرؤوسين (0..*)، وكل مرؤوس لديه صفر أو مدير واحد (0..1) — الرئيس التنفيذي في القمة ليس لديه مدير. يُرسم هذا كخط حلقي يعود من الفئة إلى نفسها.

لماذا تهم دقة التعددية: كتابة * بدلاً من 1..* تبدو تفصيلاً صغيراً، لكنها تغير القاعدة التجارية. طلب يمكن أن يكون له صفر عناصر غير مقبول قانونياً. موعد لا ينتمي لأي مريض هو سجل يتيم. تعدديتك هي قاعدة تجارية رسمية يجب على أصحاب المصلحة مراجعتها والموافقة عليها.

أخطاء شائعة يجب تجنبها

  • تبديل الطرفين. التعددية بجانب فئة تصف عدد نسخ تلك الفئة المشاركة، لا عدد نسخ الفئة الأخرى. تحقق دائماً بقراءة الاتجاهين بصوت عالٍ.
  • نسيان الصفر. هل الارتباط إلزامي؟ إذا كان منتج جديد يمكن أن يوجد قبل أن تشير إليه أي عنصر طلب، فطرف OrderItem هو * وليس 1..*.
  • تكرار الارتباطات. إذا كان للفئتين ارتباط بالفعل، لا ترسم خطاً ثانياً لكل عملية. العمليات وقابلية التنقل تُنمذج بشكل منفصل؛ الخط البنيوي يُرسم مرة واحدة.
  • ارتباط بلا اسم في مخطط مزدحم. عندما يحتوي المخطط على أكثر من ثلاث فئات، سمِّ كل ارتباط أو أضف أسماء أدوار حتى لا يضطر القراء إلى التخمين.
الارتباط مقابل الاعتمادية: الارتباط يعني رابطاً بنيوياً مستمراً (كائن يحتفظ بمرجع لكائن آخر). الاعتمادية (سهم منقط) هي علاقة أضعف وعابرة — فئة تستخدم أخرى كمعامل في دالة لكن لا تخزنها. لا ترسم خط ارتباط صلب لاعتمادية.

استخلاص الارتباطات من المتطلبات

عند قراءة وثيقة المتطلبات أو إجراء المقابلات مع أصحاب المصلحة، استمع إلى:

  • العبارات الفعلية بين الأسماء → ارتباطات مرشحة ("أمين المكتبة يُصدر قرض").
  • كلمات الملكية والاحتواء → مؤشرات التعددية ("يجب أن تحتوي كل فاتورة على عنصر واحد على الأقل"1..*).
  • لغة الاختياري/الإلزامي → صفر أو واحد مقابل واحد بالضبط ("قد يُقدم العميل اختيارياً عنوان تسليم"0..1 على DeliveryAddress).

الارتباطات وقيم تعدديتها كثيراً ما تكون الجزء الأكثر جدلاً في نموذج المجال خلال مراجعات أصحاب المصلحة — وهذا أمر مشروع، لأنها تُرسّخ قواعد تجارية ملموسة. إتقانها مبكراً يمنع تغييرات مكلفة في مخطط قاعدة البيانات لاحقاً.