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

التجميع والتركيب

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

التجميع والتركيب

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

فهم هذا الفرق من أعملي المهارات التي يطوّرها المحلل: إذ يُحدد ما إذا كان حذف سجل أب يجب أن يتتالى إلى الأبناء، وما إذا كانت الأجزاء مشتركة بين آباء متعددين، ومدى الترابط أو الاستقلالية بين المكونات.

استعارة المعين المشترك

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

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

المخطط الأول — الترميزان جنباً إلى جنب

يُظهر المخطط أدناه كلا الترميزين مع تسميات توضيحية حتى تحفظ الأشكال قبل تطبيقها على سيناريو حقيقي.

Aggregation vs Composition Notation Department - name (operations) Employee - empId (operations) 1 * Hollow ◇ = Aggregation Aggregation lifecycle: Employee exists independently; can move to another Department Order - orderId (operations) OrderLine - qty (operations) 1 1..* Filled ◆ = Composition Composition lifecycle: OrderLine is deleted when its Order is deleted
مقارنة جنباً إلى جنب: المعين المجوف (التجميع) بين Department وEmployee، مقابل المعين المملوء (التركيب) بين Order وOrderLine.

التجميع بالتفصيل: مثال القسم والموظف

لدى متجر إلكتروني أقسام (التسويق، الهندسة، اللوجستيك) وموظفون ينتمون إلى قسم. هذا سيناريو تجميع كلاسيكي:

  • يمتلك Employee وجوداً مستقلاً: قبل إسناده إلى أي قسم فهو موجود في نظام الموارد البشرية. وبعد مغادرة القسم قد ينتقل إلى قسم آخر، أو قد تُعيد الشركة هيكلتها وتلغي قسماً مع الاحتفاظ بموظفيه.
  • حذف سجل قسم التسويق لا يحذف سجلات Employee؛ يُعاد تعيين هؤلاء الموظفين أو يُضبط مفتاحهم الأجنبي على null.
  • في بعض المؤسسات يمكن للموظف الانتماء إلى أقسام متعددة (تجميع بمشاركة الجزء). يُجيز UML ذلك في التجميع لا في التركيب.

يُضع المعين المجوف على طرف Department (الكل) بتعددية 1، وعلى طرف Employee (الجزء) بتعددية * (صفر أو أكثر من الموظفين للقسم).

أثر قاعدة البيانات: يُعيَّن التجميع عادةً إلى مفتاح أجنبي يقبل القيمة الفارغة في جدول الجزء. يسمح employees.department_id بـ NULL حتى يمكن لموظف الوجود بلا قسم، ويكون ON DELETE SET NULL (أو بلا تتالٍ) الافتراض الآمن.

التركيب بالتفصيل: مثال الطلب وبند الطلب

في المتجر الإلكتروني نفسه، يضع العميل Order ويحتوي كل طلب على بند أو أكثر من نوع OrderLine (كل بند يُسجّل منتجاً وكمية وسعراً). هذه علاقة تركيب لأن:

  • ليس لـ OrderLine معنى خارج طلبه الأب. "الكمية: 2، السعر: 49.99" لا معنى له إن لم تعرف إلى أي طلب ينتمي.
  • عند الحذف الدائم للطلب (مثلاً تنظيف الطلبات الملغاة)، يُحذف كل OrderLine المرتبط به — قواعد العمل تفرضه ونموذج البيانات يُطبّقه.
  • لا يمكن لـ OrderLine الانتماء إلى طلبين مختلفين في آنٍ واحد.

يقع المعين المملوء على طرف Order بتعددية 1. يحمل طرف OrderLine تعددية 1..* (يجب أن يحتوي كل طلب على بند واحد على الأقل).

أثر قاعدة البيانات: يُعيَّن التركيب إلى مفتاح أجنبي غير قابل للإفراغ مع تتالٍ عند الحذف. order_lines.order_id NOT NULL مع ON DELETE CASCADE يُطبّق حذف البنود مع طلبها الأب.

المخطط الثاني — نظام المكتبة: كلتا العلاقتين معاً

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

  • لدى Library كثير من سجلات Book — لكن الكتب يمكن نقلها إلى فرع آخر أو بيعها؛ فهي موجودة باستقلالية عن أي مكتبة بعينها. تجميع.
  • يتألف Book من كائنات Chapter — فالفصل لا هوية له ولا معنى خارج كتابه؛ حذف سجل الكتاب يدمر سجلات فصوله كلها. تركيب.
  • سجل Loan يتألف من إدخالات LoanItem (واحدة لكل كتاب في إعارة متعددة الكتب) — لا يمكن لبنود الإعارة البقاء بعد سجل الإعارة الأب. تركيب.
Library System — Aggregation and Composition Library - libraryId + searchBooks() Book - isbn - title + getDetails() 1 * aggregation Chapter - chapterNo + getContent() 1 1..* composition Loan - loanDate + close() LoanItem - dueDate + renew() 1 1..* composition Legend Aggregation Composition
مخطط فئات نظام المكتبة يُظهر التجميع (Library — Book، معين مجوف) والتركيب (Book — Chapter وLoan — LoanItem، معين مملوء) مع تسميات التعددية.

قراءة مخطط المكتبة

مرّ على كل علاقة وتحقق من سؤالي دورة الحياة:

  1. Library ◇ — * Book (تجميع): يمكن للكتاب الوجود في كتالوج باستقلالية عن أي فرع مكتبة. عند إغلاق فرع، تُنقل كتبه لا تُدمَّر. وجود مستقل؟ نعم. مشاركة محتملة؟ نعم. النتيجة: تجميع.
  2. Book ◆ — 1..* Chapter (تركيب): للفصل (مثلاً "الفصل الثالث") لا هوية ولا غاية بدون كتابه. إذا حُذف سجل الكتاب حُذفت سجلات فصوله كلها. وجود مستقل؟ لا. ينتمي إلى كتاب واحد فقط؟ نعم. النتيجة: تركيب.
  3. Loan ◆ — 1..* LoanItem (تركيب): لبند الإعارة (كتاب محدد في معاملة إعارة محددة) لا معنى خارج معاملة الإعارة الأم. إغلاق سجل الإعارة وحذفه يجب أن يتتالى إلى بنوده. النتيجة: تركيب.

قائمة تحقق عملية للقرار

عند مواجهة علاقة كل بجزء محتملة أثناء تحليل المتطلبات، مرّ على هذه الأسئلة الأربعة بالترتيب:

  1. هل هذه بالفعل علاقة كل بجزء؟ إذا كانت الفئتان تعرف إحداهما الأخرى ببساطة (مثلاً Customer يضع Order)، فهذا ارتباط عادي لا تجميع ولا تركيب.
  2. هل يستطيع الجزء الوجود بدون الكل؟ إذا كانت الإجابة نعم — تجميع. إذا لا — فكّر في التركيب.
  3. هل يمكن للجزء الانتماء إلى أكثر من كل في آنٍ واحد؟ إذا نعم — تجميع (مشترك). إذا لا — اتجه نحو التركيب.
  4. عند تدمير الكل هل يجب تدمير الجزء معه؟ إذا نعم — تركيب. إذا لا — تجميع.

أخطاء المحللين الشائعة

الإفراط في استخدام التركيب: خطأ متكرر هو استخدام المعين المملوء مع كل علاقة "يمتلك". تساءل دائماً هل يبقى الجزء بعد أبيه. لدى Company كائنات Employee — لكن الموظفين ليسوا مُركَّبين داخل الشركة؛ فهم موجودون باستقلالية ويمكنهم المغادرة. استخدم التجميع.
الخلط بين التركيب والوراثة: التركيب علاقة كل بجزء ("الطلب يحتوي بنوداً")؛ والوراثة علاقة تصنيف ("حساب التوفير هو نوع من حسابات البنك"). هما سهمان مختلفان تماماً في UML. لا تستخدم أبداً المعين المملوء للإشارة إلى أن فئة تخصص فئة أخرى.

خلاصة

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