نمذجة UML
درس 4 من 5
4نمذجة UML: لغة رسم الأنظمة البرمجية
الصورة الكبيرةكل ما تحتاج فهمه عن UML Class Diagrams و Sequence Diagrams، والعلاقات الست بين الكلاسات، بأمثلة بايثون ورسومات Mermaid جاهزة.
ماذا تشاهد في الرسم: صندوق الصنف يتكوّن من ثلاث طبقات: الاسم ثم السمات ثم الطرق. ثم يربطه خط بصنف آخر، والنجمة على الطرفين تعني «عدد غير محدود».
خارطة هذا الجزء
المفاهيم بالترتيب، اضغط أيًّا منها للقفز إليه:
طريقان إلى نفس الفكرة
UML مثل المخطط الهندسي للبيت قبل البناء. مخطط الأصناف يريك الغرف وكيف تتصل ببعضها، ومخطط التسلسل يريك من يمشي إلى أين وبأي ترتيب في يوم عادي. الرسم يكشف الخطأ وهو ما زال خطًّا على ورق، قبل أن يصير جدارًا يصعب هدمه.
مخطط الأصناف Class Diagram يصف كل صنف بسماته وتوابعه، والعلاقات الست: الارتباط والتعميم والتجميع والتركيب والتحقيق والاعتماد، مع أرقام التعدد 1..*. ومخطط التسلسل Sequence Diagram يصف تبادل الرسائل عبر الزمن، وMermaid يكتب المخططين نصًا يُحفظ مع الكود.
الأساسيات المطلوبة
قبل أن تتعمّق في UML، تأكد أنك مرتاح مع هذه المفاهيم من البرمجة الكائنية (الأجزاء 6-8 أعلاه):
| المفهوم | لماذا يهمّك هنا |
|---|---|
| Class / Object | UML أساسًا يرسم الكلاسات وعلاقاتها، إن لم تفهم الفرق بين الكلاس والكائن، الرسم لن يعني لك شيئًا. |
| Attributes / Methods | كل صندوق كلاس في UML يعرض خصائصه وميثوداته، هي نفس ما تكتبه داخل __init__ ودوال الكلاس. |
| Inheritance | أحد أهم ستة علاقات في UML (Generalization) هو ببساطة الوراثة التي تعرفها بصيغة class Dog(Animal). |
| Abstract Classes | ستحتاجها لفهم علاقة Realization (تنفيذ واجهة/Interface). |
لمحة سريعة قبل درسَي UML وأنماط التصميم
- الجزء التاسع (UML) يعلّمك كيف "ترسم" تصميم نظام برمجي قبل كتابة أي سطر كود، لغة بصرية موحّدة يفهمها كل المبرمجين بغض النظر عن لغة البرمجة.
- الجزء العاشر (Design Patterns) يعلّمك حلولاً جاهزة ومجرَّبة لمشاكل تصميم متكررة: كيف تُنشئ الكائنات، وكيف تجعلها تتواصل، وكيف توسّع سلوكها دون كسر الكود القديم.
- الجزآن في الحقيقة وجهان لعملة واحدة: الأول يعلّمك كيف تُوثّق بنية نظامك، والثاني يعلّمك كيف تصمّم بنية جيدة من الأساس. UML هي اللغة، و Design Patterns هي المفردات الجاهزة في تلك اللغة.
المفاهيم الأساسية
UML (Unified Modeling Language) هي لغة بصرية موحّدة، مخطط هندسي (blueprint)، تُستخدم لتمثيل تصميم أي نظام برمجي قبل أو أثناء كتابة الكود. بدلًا من شرح تصميمك بجُمل طويلة، ترسمه بصناديق وأسهم يفهمها أي مبرمج آخر مباشرة.
1لماذا نستخدم UML أصلاً؟
لتصوّر العلاقات بين الكلاسات قبل الكتابة، لتوفير وقت إعادة الهيكلة (refactoring) لاحقًا، ولتوصيل فكرة التصميم لبقية الفريق بلغة مشتركة لا تعتمد على لغة برمجة معيّنة.
2Class Diagram
يُظهر البنية الثابتة للنظام: ما هي الكلاسات، وما خصائصها وميثوداتها، وكيف ترتبط ببعضها. هو "صورة ساكنة" للنظام.
3Sequence Diagram
يُظهر السلوك عبر الزمن: من يستدعي مَن، وبأي ترتيب، أثناء تنفيذ سيناريو محدد. هو "فيديو" لحدث واحد وليس صورة ثابتة.
4لماذا Mermaid؟
Mermaid هي صيغة نصية بسيطة لرسم مخططات UML (وغيرها) بكتابة كود بدل السحب والإفلات، وهذا يجعلها قابلة للتخزين في Git ومراجعتها مثل أي كود آخر، ولهذا تُحفظ المخططات بصيغة .mmd مع الكود.
5تشريح صندوق الكلاس في UML
كل كلاس في مخطط UML يُرسم كصندوق من ثلاث طبقات:
- title: str
- is_available: bool
+ mark_as_available()
+ mark_as_unavailable()
إشارة (−) تعني خاص Private، وإشارة (+) تعني عام Public: تمامًا كاصطلاحات بايثون (شرطة سفلية واحدة أو مزدوجة).
6العلاقات الست بين الكلاسات
هذا هو قلب المشروع: أي مخطط UML صحيح يعتمد على اختيار العلاقة الصحيحة بين كل كلاسين. الفرق بينها غالبًا سؤال واحد: هل يستطيع أحد الطرفين أن يوجد بدون الآخر؟
الرسم 8: أربع علاقات "بنيوية" أساسية في UML، من الأضعف ارتباطًا (Association) إلى الأقوى (Composition/Generalization).
| العلاقة | الرمز | المعنى | مثال | هل يعيش الطرف الآخر بدونه؟ |
|---|---|---|---|---|
| Association | --> | علاقة استخدام عامة بين كلاسين مستقلَّين | معلّم ↔ طالب | نعم، دائمًا |
| Generalization | --|> | علاقة "هو نوع من"، الوراثة | Dog يرث من Animal | غير منطقي أصلاً (نوع فرعي) |
| Aggregation | o-- | "كل-جزء" لكن الجزء مستقل الحياة | قسم ↔ موظف | نعم، الموظف يبقى موجودًا |
| Composition | *-- | "كل-جزء" لكن الجزء يموت بموت الكل | حاسوب ↔ معالج | لا، يُحذف معه |
| Realization | ..|> | كلاس يُنفّذ عقد واجهة (Interface) | Dog يُنفّذ Animal المجرّدة | ، |
| Dependency | ..> | اعتماد مؤقت وقت التنفيذ فقط | ReportGenerator يعتمد على DataFetcher | نعم، الاعتماد لحظي فقط |
الرسم 9: Realization (تنفيذ واجهة) و Dependency (اعتماد مؤقت): كلاهما بخط منقّط، لكن الفرق أن الأول التزام دائم بعقد، والثاني استخدام عابر.
أمثلة بايثون سريعة لكل علاقة
7Association
class Teacher:
def __init__(self, name):
self.name = name
self.students = []
class Student:
def __init__(self, name):
self.name = name
8Generalization
class Animal:
def speak(self):
raise NotImplementedError
class Dog(Animal):
def speak(self):
return "Woof!"
9Aggregation
class Department:
def __init__(self, name):
self.name = name
self.employees = [] # independent lifecycle
class Employee:
def __init__(self, name):
self.name = name
10Composition
class Computer:
def __init__(self, speed):
# Processor is created and destroyed with it
self.processor = Processor(speed)
class Processor:
def __init__(self, speed):
self.speed = speed
11Realization
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def speak(self): ...
class Cat(Animal):
def speak(self):
return "Meow!"
12Dependency
class DataFetcher:
@staticmethod
def fetch():
return "data"
class ReportGenerator:
def generate(self):
data = DataFetcher.fetch()
return f"Report: {data}"
Sequence Diagram: كيف تُظهر السلوك عبر الزمن؟
بينما Class Diagram يجيب عن سؤال "ما هي الأجزاء؟"، فإن Sequence Diagram يجيب عن سؤال "ماذا يحدث بالضبط، وبأي ترتيب، عندما يقع حدث معيّن؟"، مثلاً "ماذا يحدث عند إنشاء استعارة جديدة؟"
الرسم 10: عناصر Sequence Diagram الأساسية: الخط الرأسي (Lifeline) لكل كائن، شريط التفعيل (Activation)، والأسهم بأنواعها الثلاثة.
| العنصر | الشكل | المعنى |
|---|---|---|
| Lifeline | خط رأسي منقّط تحت كل مشارك | يمثّل وجود الكائن عبر الزمن |
| Activation Bar | مستطيل رفيع على الخط | الفترة التي يكون فيها الكائن "نشطًا" يعالج طلبًا |
| رسالة متزامنة (Sync) | سهم مصمت (→) | المرسِل ينتظر الرد قبل المتابعة |
| رسالة غير متزامنة (Async) | سهم مفتوح (⇢) | المرسِل يكمل عمله دون انتظار |
| رسالة الرجوع (Return) | سهم متقطّع | الرد النهائي من المستقبِل للمرسِل |
مثال تطبيقي كامل: نظام تسجيل الطلاب بالمقررات
لتثبيت الفكرة بمثال مختلف تمامًا عن مشروعك (حتى تتدرّب على تطبيق نفس المنطق بنفسك لاحقًا على نظامك)، لنموذج نظام تسجيل جامعي بسيط:
- Student: له اسم وبريد إلكتروني، ويمكنه التسجيل في مقررات.
- Course: له عنوان وعدد ساعات، مستقل تمامًا عن أي طالب معيّن.
- Enrollment: يمثّل ربط طالب بمقرر في تاريخ معيّن، ولا معنى له بدون الاثنين معًا (Composition من جهة العملية).
الرسم 11: لاحظ العدد 1 و * على طرفي كل علاقة: هذه هي التعدّدية (Multiplicity): طالب واحد قد يملك عدة تسجيلات، ومقرر واحد يظهر في عدة تسجيلات.
الرسم 12: نفس النظام، لكن بمنظور "ماذا يحدث لحظة تسجيل طالب في مقرر" بدل "ما هي الأجزاء الثابتة".
خرافة مقابل حقيقة
| الخرافة | الحقيقة |
|---|---|
| UML أداة قديمة لا يستخدمها أحد اليوم | لا تزال تُستخدم يوميًا في التوثيق التقني، مراجعات التصميم (Design Reviews)، ومقابلات System Design. |
| يجب رسم كل تفصيلة في النظام بـ UML | الهدف هو التواصل الواضح، لا التغطية الكاملة، أفضل مخطط هو الأبسط الذي يوصل الفكرة. |
| Aggregation و Composition نفس الشيء تقريبًا | الفرق جوهري: من يتحكم بدورة حياة الجزء؟ هذا يغيّر قرارات برمجية حقيقية (متى يُحذف الجزء تلقائيًا؟). |
| Sequence Diagram يُستخدم فقط للتوثيق النهائي | هو أداة تفكير مبكرة ممتازة لاكتشاف ثغرات في التصميم قبل كتابة أي كود. |
أين تُستخدم UML فعليًا؟
تصميم الأنظمة قبل البناء
فرق الهندسة الكبيرة ترسم Class/Sequence Diagrams قبل كتابة الكود لتوحيد الفهم بين المطورين.
مقابلات System Design
يُطلب منك غالبًا رسم مخطط سريع لتوضيح كيف تتفاعل مكوّنات نظامك المقترح.
التوثيق التقني
مخططات UML تُدرَج في مستندات هندسة البرمجيات (ADRs، RFCs) لتوصيل قرارات التصميم.
مراجعة الكود القديم (Legacy)
عند التعامل مع كود قديم معقّد، رسم مخطط عكسي (Reverse Engineering) يساعد على فهم بنيته بسرعة.
جرّب بنفسك
في مخطّط الأصناف، ماذا تعني - قبل اسم السمة؟
- تعني خاصة و+ تعني عامة. الرمز يقول من يستطيع الوصول إليها، لا شيء عن قيمتها.
بطاقات مراجعة سريعة
اختبر فهمك
1. ما الفرق العملي بين Aggregation و Composition؟
في Aggregation، الجزء يستمر بالوجود حتى لو حُذف الكل (مثال: موظف يبقى موجودًا لو حُذف القسم). في Composition، الجزء يُحذف تلقائيًا مع الكل لأنه لا معنى له بمفرده (مثال: المعالج يُحذف مع الحاسوب).
2. متى تستخدم Realization بدلاً من Generalization؟
Generalization للوراثة الفعلية من كلاس فعلي (is-a حقيقي). Realization عندما ينفّذ كلاس عقد واجهة مجرّدة (Abstract Class / Interface) بدون وراثة سلوك جاهز، فقط التزام بتوقيع الميثودات.
3. لماذا يهتم Sequence Diagram بالترتيب الزمني بينما Class Diagram لا يهتم به؟
لأنهما يجيبان عن سؤالين مختلفين تمامًا: Class Diagram يوثّق البنية الثابتة (structure) بينما Sequence Diagram يوثّق سيناريو تنفيذ واحد محدد بترتيبه الزمني (behavior)، نفس النظام قد يكون له مخطط بنية واحد لكن عشرات مخططات السلوك لسيناريوهات مختلفة.
4. في نظام "مكتبة"، لماذا Loan تحديدًا Composition مع Library وليس Aggregation؟
لأن سجل الاستعارة (Loan) لا معنى منطقي لوجوده مستقلاً بدون سياق مكتبة تديره، دورة حياته مرتبطة بالكامل بالعملية التي أنشأته، بخلاف الكتاب أو المستخدم اللذين يستمران بالوجود بمعزل عن أي مكتبة معيّنة.
مصادر هذا الدرس
مرتّبة بالنوع. ابدأ بالتوثيق الرسمي إذا تبي المرجع الدقيق، وبالمقال أو الفيديو إذا تبي الشرح أولًا.
مقالات2
خلّصت الدرس؟
سجّل الدخول ليُحفظ تقدّمك.