محرر مخططات الأصناف بـ Mermaid
يبيّن مخطط الأصناف الأنواعَ وعلاقاتِ بعضها ببعض: ما الذي يحتوي ماذا، وما الذي يرث عمّن، وما الذي يعتمد على ماذا. يناسبك حين يكون الجوهر شكلَ الشيفرة — نموذج مجال، واجهة توسعة، شجرة وراثة. أما إن أردت إظهار ما يجري وقت التشغيل لا كيف تتلاءم الأنواع، فاستعمل مخطط التسلسل.
نموذج مجال الدفع
ثلاثة أنواع من العلاقات في مخطط واحد: التركيب للأجزاء التي لا تبقى بعد الكل، والوراثة لتسلسل وسائل الدفع، وارتباط عادي بتعدّدية. والمعنى تحمله الأسهم أساسًا؛ أما مستطيلات الأصناف فتكاد تكون تابعًا.
classDiagram
class طلب {
+String رقم
+حالةالطلب حالة
+مبلغ الإجمالي()
+void أضفسطرًا(منتج م, int كمية)
}
class سطرالطلب {
+منتج المنتج
+int الكمية
+مبلغ القيمة()
}
class وسيلةالدفع {
<<abstract>>
+فوّض(مبلغ القيمة) bool
}
class بطاقة {
+String آخرأربعة
+فوّض(مبلغ القيمة) bool
}
class حوالة {
+String آيبان
+فوّض(مبلغ القيمة) bool
}
class دفععندالاستلام {
+مبلغ رسمالتحصيل
+فوّض(مبلغ القيمة) bool
}
طلب "1" *-- "1..*" سطرالطلب : يحتوي
طلب --> وسيلةالدفع : يُدفع بـ
وسيلةالدفع <|-- بطاقة
وسيلةالدفع <|-- حوالة
وسيلةالدفع <|-- دفععندالاستلامأمثلة مشروحة
١. صنف واحد
الرمز `+` يعني عامًا، و`-` خاصًا، و`#` محميًا. والعضو الذي فيه قوسان يُرسم دالة؛ وبدونهما يكون حقلًا.
classDiagram
class مستخدم {
+String بريد
-String بصمةكلمةالمرور
+bool تحقق(String مرشح)
}٢. الوراثة والواجهات
الرمز `<|--` وراثة، ويُقرأ «الذي على اليمين يوسّع الذي على اليسار». والتعليق `<<interface>>` تسمية لا سلوك، لكنه هو ما يحدد وضوح المخطط.
classDiagram
class مستودع {
<<interface>>
+جد(String معرف) كيان
+احفظ(كيان ك) void
}
class مستودعPostgres {
-اتصال الاتصال
+جد(String معرف) كيان
+احفظ(كيان ك) void
}
class مستودعذاكرة {
-Map التخزين
+جد(String معرف) كيان
+احفظ(كيان ك) void
}
مستودع <|.. مستودعPostgres
مستودع <|.. مستودعذاكرة٣. التركيب في مقابل التجميع
الفرق يتعلق بمدة الحياة. فالمعيّن الممتلئ (`*--`) يعني أن الجزء يزول مع الكل: احذف الفاتورة تختفِ سطورها. والمعيّن الفارغ (`o--`) يعني أن الجزء قائم بذاته.
classDiagram
class فاتورة {
+String رقم
}
class سطرفاتورة {
+String بيان
}
class عميل {
+String الاسمالتجاري
}
فاتورة "1" *-- "1..*" سطرفاتورة : تتكون من
عميل "1" o-- "0..*" فاتورة : صدرت له٤. الأنواع العامة
علامات المدّة تعطي وسائط الأنواع: `مستودع~مستخدم~`. والتداخل يعمل كذلك، وهو لازم أحيانًا ونادرًا ما يكون فكرة جيدة. والحروف العربية تعمل داخل النوع العام دون عائق.
classDiagram
class مستودع~T~ {
+جد(String معرف) T
+الكل() List~T~
}
class مخبأ~K, V~ {
+خذ(K مفتاح) V
+ضع(K مفتاح, V قيمة) void
}
class مستودعالمستخدمين {
+جدبالبريد(String بريد) مستخدم
}
مستودع~مستخدم~ <|-- مستودعالمستخدمين٥. الملاحظات والاتجاه
الوسم `direction LR` يخطّط المخطط من اليسار إلى اليمين، وهو ما يخدم شجرة الوراثة عادةً أكثر من التخطيط الافتراضي. والملاحظة هي الموضع الصحيح للقيد الذي لا يتسع له مستطيل الصنف.
classDiagram
direction LR
class مخزنالأحداث {
+ألحق(حدث ح) void
+أعدالتشغيل(String تيار) List~حدث~
}
class لقطة {
+int إصدار
+byte[] محتوى
}
مخزنالأحداث --> لقطة : يكتب كل 100 حدث
note for مخزنالأحداث "إلحاق فقط. لا تُعدّل الأحداث ولا تُحذف أبدًا."ملخص صياغة مخطط الأصناف
أسهم العلاقات تستحق الحفظ: فهي التي تميّز مخطط الأصناف عن رسم مستطيلات وخطوط، وتُقرأ من الرأس إلى الخلف، وهو ما يضلّل مدة طويلة.
| الصياغة | المعنى |
|---|---|
| classDiagram | يفتح المخطط. حساس لحالة الأحرف. |
| class اسم { ... } | صنف بأعضائه. والقوس المعقوف المُغلِق في سطر مستقل. |
| +عضو | عام. |
| -عضو | خاص. |
| #عضو | محمي. |
| +دالة(نوع وسيط) نوعالإرجاع | دالة — والقوسان هما ما يجعلانها كذلك. |
| <<interface>> / <<abstract>> | نمط، يُكتب في السطر الأول داخل الصنف. |
| A <|-- B | وراثة: B يوسّع A. |
| A <|.. B | تحقيق: B ينفّذ الواجهة A. |
| A *-- B | تركيب: B لا يبقى بعد A. |
| A o-- B | تجميع: B يمكن أن يوجد بدون A. |
| A --> B | ارتباط باتجاه. |
| A ..> B | اعتمادية — A يستعمل B ولا يحتفظ به. |
| A "1" --> "0..*" B : تسمية | تعدّدية على الطرفين مع تسمية العلاقة. |
| class مستودع~T~ | وسيط نوع عام. |
| note for A "نص" | ملاحظة ملحقة بصنف. |
| direction LR | يغيّر اتجاه التخطيط. |
الأخطاء التي تُفسد مخطط الأصناف
أُعيد إنتاجها على Mermaid 11.12.2. ومخطط الأصناف من الأنواع الأكثر تسامحًا بين الستة، ولذلك يُرسم نصف هذه الأخطاء بهدوء ويعطيك الصورة الخاطئة.
ما تراه
Parse error ينتهي بـ: got 'EOF_IN_STRUCT'
لماذا
جسم صنف فُتح بـ `{` ولم يُغلق قط. وهنا يفيد اسم الرمز فعلًا: فهو يقول إن الملف انتهى ونحن ما زلنا داخل صنف.
الحل
أغلق القوس المعقوف في سطر مستقل.
classDiagram
class طلب {
+String رقمclassDiagram
class طلب {
+String رقم
}ما تراه
Parse error ينتهي بـ: got 'ANNOTATION_END'
لماذا
سهم من مخطط التسلسل استُعمل في مخطط أصناف. فالرمز `->>` لا يعني هنا شيئًا، ويتوغل فيه المحلل بما يكفي ليعيد اسم رمز مضلِّلًا.
الحل
استعمل علاقات مخطط الأصناف: `-->` للارتباط، و`<|--` للوراثة، و`*--` للتركيب.
classDiagram
طلب ->> عميلclassDiagram
طلب --> عميل : يخصما تراه
No diagram type detected matching given configuration
لماذا
حالة أحرف خاطئة في الكلمة المفتاحية. فـ `classdiagram` ليست `classDiagram`.
الحل
حرف D كبير.
classdiagram
class طلبclassDiagram
class طلبما تراه
السهم يشير إلى الجهة المعاكسة لما أردت
لماذا
أسهم العلاقات تُقرأ من الرأس إلى الخلف. فـ `A <|-- B` تعني أن B يرث من A لا العكس. وإن كتبتها معكوسة رُسمت رغم ذلك — إلا أنها الآن تزعم أن الصنف الأساس يوسّع صنفه الفرعي.
الحل
اقرأها هكذا: «الطرف البعيد يوسّع الطرف ذا الرأس». وضع الأب على يسار `<|--`.
classDiagram
بطاقة <|-- وسيلةالدفعclassDiagram
وسيلةالدفع <|-- بطاقةما تراه
يظهر حقل في موضع توقعت فيه دالة
لماذا
القوسان هما الشيء الوحيد الذي يميّز الدالة عن الحقل. فـ `+احفظ` حقل اسمه احفظ؛ و`+احفظ()` دالة. وكلا الشكلين صحيح، فلا شيء ينبّه.
الحل
أضف القوسين، ثم نوع الإرجاع بعدهما إن أردت رؤيته.
classDiagram
class مستودع {
+احفظ
+جد
}classDiagram
class مستودع {
+احفظ(كيان ك) void
+جد(String معرف) كيان
}ما تراه
التركيب والتجميع يبدوان للوهلة الأولى متطابقين ويقولان عكس بعضهما
لماذا
الرمزان `*--` و`o--` يفترقان بمحرف واحد، وهما يرمّزان فرقًا معنويًا حقيقيًا: أيبقى الجزء بعد الكل أم لا. واستعمال الخطأ منهما ينتج مخططًا صحيحًا شكلًا وكاذبًا على مجالك.
الحل
معيّن ممتلئ `*--` حين يؤدي حذف الأب إلى حذف الابن. وفارغ `o--` حين لا يؤدي.
classDiagram
طلب o-- سطرالطلب : يحتويclassDiagram
طلب *-- سطرالطلب : يحتويملاحظات على الرسم
مقيس على Mermaid 11.12.2، وهي النسخة التي يستعملها هذا الموقع.
ينمو إلى أعلى أسرع من أي نوع آخر هنا
قِيس على أصناف بعضوين لكل صنف مربوطة بالوراثة: ثلاثة أصناف تعطي إطارًا يقارب 176×548، وأربعون صنفًا تعطي 180×7726، أي نحو 194 بكسل ارتفاعًا لكل صنف — وهو أشد نمو في الأنواع الستة على هذا الموقع. ومخطط بأربعين صنفًا يتجاوز سبعة آلاف بكسل ارتفاعًا ولا ينفع صورةً واحدة. و`direction LR` يساعد، لكن فوق خمسة عشر صنفًا تقريبًا يكون الحل الصادق تقسيمَ المخطط بحسب حدود المجال.
الأسماء العربية تعمل أسماءَ أصناف ودوال
جُرّب: `class طلب` يُرسم، و`+String رقم` يظهر حقلًا، و`+مبلغ الإجمالي()` تنتقل إلى خانة الدوال كما ينبغي — أي إن القوسين يعملان مع الأسماء العربية تمامًا كما مع اللاتينية. والقيد الوحيد هو المسافة داخل اسم الصنف نفسه، لأنه معرّف: فـ `سطر الطلب` لا يصلح ويجب وصله `سطرالطلب`. أما تسمية العلاقة بعد النقطتين فنص حر، فتُكتب `: يُدفع بـ` بمسافاتها كاملة.
عدد الأعضاء لا يكاد يؤثر في العرض
العرض يحدده أطولُ توقيع لعضو واحد لا عددُ الأعضاء. فالصنف ذو العشرين حقلًا القصيرة ليس أعرض من ذي الثلاثة. بعبارة أخرى: كن سخيًا مع الأعضاء وشحيحًا مع الأصناف، وهو عكس ما تمليه الغريزة تمامًا. وفي العربية تخرج التواقيع أضيق منها في الإنجليزية، فيميل العرض إلى أن يكون أقل مما تتوقعه من مثال إنجليزي.
الأنواع العامة تستعمل علامة المدّة ولذلك تبعة
الصيغة `مستودع~T~` كُتبت هكذا لأن الأقواس الزاوية تتعارض مع HTML في التسميات. ويتبع ذلك أيضًا أن علامة مدّة حقيقية داخل اسم صنف أو عضو ستُقرأ بداية وسيط نوع. وهذا نادر، لكنه حين يقع يربك إرباكًا لا يستهان به.
التسميات HTML، فتصدير PNG يعيد الرسم
تُرسم تسميات الأصناف داخل `<foreignObject>` في ملف SVG، وترفض المتصفحات تحويل ذلك إلى صورة نقطية على لوحة canvas. وكان تصدير PNG في هذا الموقع يفشل بصمت ويعيد ملف SVG؛ أما الآن فيعيد رسم المخطط أولًا بتسميات نصية SVG صِرفة. فيخرج الـ PNG صحيحًا وبحجمه الكامل، بتنضيد يختلف قليلًا عما على الشاشة.
متى يكون مخطط آخر أنسب
إن كنت توثّق قاعدة بيانات لا نظام أنواع، فاستعمل مخطط الكيانات. والتمييز مهم: فمخططات الأصناف تنمذج السلوك والوراثة، وهما ليسا في الجداول، ومخططات الكيانات تنمذج المفاتيح والتعدّديات نمذجة متقنة، وهو ما تمرّ عليه مخططات الأصناف مرور الكرام.
وإن كان المخطط في معظمه مستطيلات موصولة بـ `-->` بلا أعضاء، فأنت ترسم معمارية لا مخطط أصناف. ومخطط تدفق بمجموعات فرعية سيبدو أفضل ويزعم أقل.
وإن كانت قائمة الأصناف تولد من الشيفرة، ففكّر إن كان ينبغي أن يولد المخطط منها كذلك. فمخطط أصناف يُصان يدويًا لقاعدة شيفرة تتغير أسبوعيًا يصير غير صادق خلال شهر، والمخطط الخاطئ أغلى من غياب المخطط.
أنواع المخططات الأخرى
بقلم Dominik Malsch · آخر تحديث: