UML: مخططات التسلسل والنشاط والحالة

مخططات آلة الحالة

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

مخططات آلة الحالة

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

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

عناصر الترميز الأساسية

تعتمد مخططات آلة الحالة على مفردات صغيرة ودقيقة:

  • الحالة الابتدائية الوهمية — دائرة مملوءة (). كل آلة حالة تبدأ منها. ليست حالة حقيقية؛ هي ببساطة سهم الدخول.
  • الحالة — مستطيل ذو زوايا مستديرة يحمل اسم الحالة (مثل: Pending، Shipped). الحالة تمثل وضعًا ينتظر فيه الكائن حدوث شيء ما.
  • الانتقال — سهم موجَّه من حالة إلى أخرى، مُعنوَن بـالحدث المُشغِّل، والحارس الاختياري بين قوسين معكوفين، والإجراء الاختياري بعد شرطة مائلة: event [guard] / action.
  • الحالة النهائية — رمز العين الثور (دائرة مملوءة داخل حلقة). تنتهي عندها دورة حياة الكائن.
الأحداث والحراس والإجراءات — اعرف الفرق:
  • الحدث (Event) هو شيء يحدث خارجيًا أو داخليًا يستطيع الكائن الاستجابة له (مثل: customerPays، timeout).
  • الحارس (Guard) شرط منطقي بين قوسين معكوفين يجب أن يكون صحيحًا لكي ينطلق الانتقال (مثل: [stock > 0]).
  • الإجراء (Action) هو النشاط الذي يُنفَّذ لحظة انطلاق الانتقال (مثل: / sendConfirmationEmail).

نمذجة دورة حياة الطلب

تأمَّل كائن Order في متجر إلكتروني. ينتقل الطلب عبر مراحل محددة بدقة من اللحظة التي يُقدِّمه فيها العميل حتى لحظة تسليمه أو إلغائه. إليك آلة الحالة التي تُجسِّد دورة الحياة الكاملة:

Order Lifecycle State Machine Diagram Pending customerPays Payment Received confirm [stock > 0] Processing dispatch / notifyCustomer Shipped delivered Delivered close cancel cancel cancel Cancelled close confirm [stock = 0] / refundPayment
آلة حالة دورة حياة الطلب: الحالات والأحداث والحراس والإجراءات عبر كامل دورة حياة الطلب.

قراءة المخطط

سِر عبر المخطط من اليسار إلى اليمين ومن الأعلى إلى الأسفل:

  1. يبدأ الطلب في حالة Pending فور إرساله.
  2. عند وقوع حدث customerPays، ينتقل الطلب إلى Payment Received.
  3. حين يحاول النظام تأكيد الطلب، يُقيَّم الحارس [stock > 0]. إن كانت المخزون متاحًا، دخل الطلب في Processing. أما إن كان المخزون صفرًا، انطلق إجراء refundPayment وعاد الطلب إلى Pending حتى يختار العميل بديلًا.
  4. عند إرسال المستودع للبضاعة (حدث dispatch)، يُطلق النظام إجراء notifyCustomer وينتقل الطلب إلى Shipped.
  5. بمجرد تأكيد التوصيل (حدث delivered)، يصل الطلب إلى Delivered ثم يُغلق.
  6. في أي وقت قبل الإرسال (Pending أو Payment Received أو Processing)، يُحرِّك حدث cancel الطلبَ إلى Cancelled الذي يُغلق هو الآخر.
نصيحة — الانتقال الذاتي: الانتقال الذي يعود إلى الحالة ذاتها (مثل إعادة محاولة دفع فاشلة) يُرسم كقوس يخرج من المستطيل ويعود إليه. يُعنوَن مثل أي انتقال آخر تمامًا.

شروط الحارس تُرسِّخ قواعد العمل

الحراس هي المكان الذي تعيش فيه قواعد العمل داخل آلات الحالة. في مخطط الطلب، يُشفِّر [stock > 0] سياسة المخزون. تأمَّل نظام حجز موعد في عيادة:

  • ينتقل الموعد من Requested إلى Confirmed فقط إن كان [الطبيب متاح في التاريخ المطلوب].
  • ينتقل إلى Completed فقط إن كان [المريض سجَّل حضوره].
  • حدث no-show مع الحارس [لم يصل المريض] يُحوِّله إلى حالة No-Show قد تُشغِّل تذكيرًا بإعادة الحجز.

بدون الحراس، ستكون الانتقالات غامضة. الحراس تحوِّل المخطط من مسودة إلى مواصفة يمكن للمطورين تنفيذها مباشرة.

الانتقالات الداخلية وإجراءات الدخول والخروج

يمكن أن تحتوي الحالة على أقسام اختيارية إضافية:

  • entry / action — يُنفَّذ مرة واحدة عند دخول الحالة (مثل: entry / startPaymentTimer).
  • exit / action — يُنفَّذ مرة واحدة عند مغادرة الحالة (مثل: exit / logTimestamp).
  • do / activity — نشاط مستمر طوال فترة البقاء في الحالة (مثل: do / processCreditCard).
متى ترسم مخطط آلة الحالة: ارسمه كلما كان لكيان واحد (طلب، سجل مريض، طلب قرض، كتاب مكتبة) دورة حياة بمراحل متعددة مُسماة وكانت العمليات الصالحة تعتمد على المرحلة الحالية. إن كانت كل عملية صالحة دائمًا بغض النظر عن التاريخ، فإن آلة الحالة لا تُضيف قيمة كبيرة — استخدم مخطط النشاط عوضًا عن ذلك.

مثال ثانٍ: كتاب المكتبة

Library Book State Machine Diagram Available checkout [member valid] Checked Out return / updateCatalog dueDatePassed [not returned] Overdue return / chargeFine, updateCatalog reserve Reserved pickup
آلة حالة كتاب المكتبة: حالات Available و Checked Out و Overdue و Reserved مع انتقالات مُدارة بالأحداث.

إرشادات رسم مخططات آلة الحالة

  1. ابدأ بالمسار السعيد. ارسم التدفق الطبيعي أولًا — تسلسل الحالات التي يمر بها الكائن حين يسير كل شيء على ما يرام.
  2. أضف مسارات الاستثناء والإلغاء. اسأل: "ماذا يمكن أن يسوء في كل حالة؟ ما الأحداث الخارجية التي يمكن أن تفرض خروجًا مبكرًا؟"
  3. سمِّ الحالات كأسماء أو صفات (Pending، Confirmed، Overdue)، لا أفعالًا.
  4. سمِّ الأحداث كعبارات فعلية أو أسماء إشارات (customerPays، dueDatePassed، cancel).
  5. تحقق من الاكتمال — يجب أن تمتلك كل حالة انتقالًا للخروج على الأقل (عدا الحالة النهائية). إذا كان الكائن قادرًا على البقاء في حالة ما إلى الأبد، فنمذج ذلك صراحةً أو أعد النظر في التصميم.
  6. تجنب كثرة الحالات. إذا تجاوزت ثماني إلى عشر حالات في مخطط واحد، فكِّر في تجميع بعضها باستخدام الحالات المركبة (موضوع الدرس القادم).
خطأ شائع — الخلط بين مخططات النشاط وآلات الحالة: كلاهما يُظهر تدفقًا، لكن الغرض مختلف. مخطط النشاط ينمذج عملية أو سير عمل (خطوات يؤديها البشر أو الأنظمة). آلة الحالة تنمذج دورة حياة كائن واحد (الأوضاع التي يمكن أن يكون فيها). إذا كنت تنمذج كيفية انتقاء المستودع للطلبات وتغليفها، فارسم مخطط نشاط. أما إذا كنت تنمذج المراحل التي يمر بها سجل الطلب ذاته، فارسم آلة حالة.

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