الوحدات والمزيج

تعديل
نسخ الدرس
تحميل الدرس

الوحدات والمزيج (Modules and Mixins)

في الدرس السابق تعلمنا الوراثة وكيف يمكن لصنف أن يرث من صنف آخر. لكن روبي تدعم وراثة فردية فقط - صنف واحد يرث من صنف أب واحد. فماذا لو أردنا مشاركة سلوكيات بين أصناف غير متعلقة؟ هنا تأتي الوحدات (Modules).

ما هي الوحدة (Module)؟

الوحدة هي حاوية لمجموعة من الدوال والثوابت. تختلف عن الصنف في أنها:

  • لا يمكن إنشاء كائنات منها (لا يوجد Module.new)
  • تُستخدم لتنظيم الشيفرة أو مشاركته بين أصناف مختلفة

إنشاء وحدة بسيطة

استخدامات الوحدات

الوحدات لها استخدامان رئيسيان:

  1. التنظيم (Namespacing): تجميع أصناف ودوال متعلقة تحت اسم واحد
  2. المزيج (Mixins): مشاركة سلوكيات بين أصناف مختلفة

الاستخدام الأول: التنظيم (Namespacing)

عندما يكبر المشروع، قد تتشابه أسماء الأصناف. الوحدات تحل هذه المشكلة:

بدون Namespacing (مشكلة)

مع Namespacing (الحل)

الوصول باستخدام ::

نستخدم :: للوصول لمحتويات الوحدة:


الاستخدام الثاني: المزيج (Mixins)

المزيج هو القوة الحقيقية للوحدات! يسمح بمشاركة دوال بين أصناف مختلفة.

المشكلة: أصناف غير متعلقة تحتاج سلوكاً مشتركاً

المشكلة: الطائر ليس طائرة، والطائرة ليست سوبرمان - لا يمكن استخدام الوراثة!

الحل: استخدام Mixin


include vs extend

include: دوال المثيل (Instance Methods)

include يجعل دوال الوحدة دوال مثيل (تُستدعى على الكائنات):

extend: دوال الصنف (Class Methods)

extend يجعل دوال الوحدة دوال صنف (تُستدعى على الصنف نفسه):

استخدام كليهما معاً


مثال عملي: نظام الصلاحيات


الوصول لمتغيرات المثيل

الوحدات يمكنها الوصول لمتغيرات المثيل @ في الصنف الذي تُخلط معه:


استخدام self في الوحدات


ترتيب البحث عن الدوال (Method Lookup)

عند استدعاء دالة، روبي تبحث بهذا الترتيب:

الترتيب:

  1. الصنف نفسه (Child)
  2. آخر وحدة مُضمّنة (B)
  3. الوحدات السابقة بالترتيب العكسي (A)
  4. الصنف الأب (Parent)
  5. الأصناف الأساسية (Object, Kernel, BasicObject)

استدعاء super في الوحدات


الوحدات المُضمّنة في روبي

روبي توفر وحدات جاهزة مفيدة جداً:

Comparable

Enumerable


جدول المقارنة

الخاصيةincludeextend
نوع الدوالدوال مثيلدوال صنف
الاستدعاءobject.methodClass.method
الاستخدام الشائعسلوكيات الكائناتأدوات مساعدة للصنف
المفهومالوصفمثال
Moduleحاوية للدوال والثوابتmodule Utils
Namespaceتنظيم الشيفرة تحت اسمMyApp::User
Mixinمشاركة سلوكياتinclude Flyable
::الوصول لمحتويات الوحدةMath::PI

أخطاء شائعة

1. نسيان الفرق بين include و extend

2. محاولة إنشاء كائن من وحدة

3. نسيان :: للوصول للمحتويات


متى نستخدم الوحدات؟

استخدم Namespacing عندما:

  • المشروع كبير ويحتاج تنظيماً
  • هناك احتمال تعارض أسماء الأصناف
  • تريد تجميع أصناف متعلقة

استخدم Mixins عندما:

  • أصناف غير متعلقة تحتاج سلوكاً مشتركاً
  • لا يمكن استخدام الوراثة (ليست علاقة "is-a")
  • تريد إعادة استخدام شيفرة عبر أصناف مختلفة

ملخص

المفهومالوصف
module Nameإنشاء وحدة
Module::ClassNamespacing للتنظيم
include Moduleإضافة دوال مثيل (Mixin)
extend Moduleإضافة دوال صنف
::الوصول لمحتويات الوحدة
ancestorsترتيب البحث عن الدوال

تمرين: نظام القدرات

حان وقت التطبيق! في محرر الشيفرة على اليسار:

المطلوب:

  1. أنشئ وحدة Speakable تحتوي على:

    • دالة speak تطبع "أتكلم!"
  2. أنشئ صنف Robot يتضمن الوحدة Speakable:

    • يحتوي على attr_reader :name
    • يحتوي على initialize(name)
  3. أنشئ صنف Animal يتضمن الوحدة Speakable:

    • يحتوي على attr_reader :name
    • يحتوي على initialize(name)
  4. أنشئ روبوت اسمه "روبي" وحيوان اسمه "بوبي"

  5. اطبع اسم كل كائن ثم استدعِ speak

الناتج المتوقع:

تلميحات:

  • ابدأ بتعريف الوحدة: module Speakable
  • استخدم include Speakable داخل كل صنف
  • لا تنسَ attr_reader :name و initialize(name)

تذكّر: الوحدات أداة قوية لتنظيم الشيفرة ومشاركة السلوكيات. استخدم Namespacing لتنظيم الأصناف، و Mixins لمشاركة الدوال بين أصناف غير متعلقة. include للدوال على الكائنات، و extend للدوال على الصنف نفسه. في الدرس القادم سنتعلم معالجة الأخطاء (Error Handling)!