ما الفرق بين التضمين والتوسيع في روبي؟
سؤال
مجرد الحصول على رأسي حول برمجة روبي.دائمًا ما تنجح وحدات mixin/modules في إرباكي.
- يشمل:يمزج في أساليب الوحدة المحددة كما طرق المثال في الفئة المستهدفة
- يمتد:يمزج في أساليب الوحدة المحددة كما أساليب الطبقة في الفئة المستهدفة
فهل الفرق الرئيسي هو هذا فقط أم أن هناك تنينًا أكبر كامنًا؟على سبيل المثال
module ReusableModule
def module_method
puts "Module Method: Hi there!"
end
end
class ClassThatIncludes
include ReusableModule
end
class ClassThatExtends
extend ReusableModule
end
puts "Include"
ClassThatIncludes.new.module_method # "Module Method: Hi there!"
puts "Extend"
ClassThatExtends.module_method # "Module Method: Hi there!"
المحلول
ما قلته هو الصحيح.ومع ذلك، هناك ما هو أكثر مما هو عليه.
إذا كان لديك فئة Klazz
والوحدة النمطية Mod
, ، مشتمل Mod
في Klazz
يعطي أمثلة Klazz
الولوج إلى Mod
أساليب.أو يمكنك تمديد Klazz
مع Mod
إعطاء فصل Klazz
الولوج إلى Mod
أساليب.ولكن يمكنك أيضًا تمديد كائن تعسفي به o.extend Mod
.في هذه الحالة يحصل الكائن الفردي Mod
أساليب على الرغم من أن جميع الكائنات الأخرى لها نفس الفئة o
لا.
نصائح أخرى
يمتد - يضيف أساليب وثوابت الوحدة المحددة إلى الفئة التعريفية للهدف (أي.فئة المفرد) على سبيل المثال
- إذا اتصلت
Klazz.extend(Mod)
, ، الآن لدى Klazz أساليب Mod (كطرق فئة) - إذا اتصلت
obj.extend(Mod)
, ، الآن obj لديه أساليب Mod (كطرق مثيل)، ولكن لا يوجد مثيل آخر لـobj.class
تمت إضافة تلك الأساليب. extend
هي طريقة عامة
يشمل - بشكل افتراضي، يتم مزجه في أساليب الوحدة المحددة كطرق مثيل في الوحدة/الفئة المستهدفة.على سبيل المثال
- إذا اتصلت
class Klazz; include Mod; end;
, ، الآن تتمتع جميع مثيلات Klazz بإمكانية الوصول إلى أساليب Mod (كطرق المثيل) include
هي طريقة خاصة، لأنها مصممة ليتم استدعاؤها من داخل فئة/وحدة الحاوية.
لكن, الوحدات في كثير من الأحيان تجاوز include
سلوك القرد عن طريق ترقيع القرد included
طريقة.هذا بارز جدًا في كود Rails القديم. مزيد من التفاصيل من يهودا كاتز.
مزيد من التفاصيل حول include
, ، بسلوكه الافتراضي، بافتراض أنك قمت بتشغيل التعليمات البرمجية التالية
class Klazz
include Mod
end
- إذا تم تضمين Mod بالفعل في Klazz، أو أحد أسلافه، فلن يكون لبيان التضمين أي تأثير
- ويتضمن أيضًا ثوابت Mod في Klazz، طالما أنها لا تتعارض
- فهو يمنح Klazz إمكانية الوصول إلى متغيرات وحدة Mod، على سبيل المثال.
@@foo
أو@@bar
- يثير ArgumentError إذا كان هناك تضمينات دورية
- إرفاق الوحدة باعتبارها السلف المباشر للمتصل (أي:فهو يضيف Mod إلى Klazz.ancestors، ولكن لا تتم إضافة Mod إلى سلسلة Klazz.superclass.superclass.superclass.لذلك، اتصل
super
في Klazz#foo سيتحقق من Mod#foo قبل التحقق من طريقة foo الخاصة بالطبقة الفائقة الحقيقية لـ Klazz.راجع RubySpec للحصول على التفاصيل.).
بالطبع، الوثائق الأساسية روبي هو دائمًا أفضل مكان للذهاب إليه لهذه الأشياء. مشروع روبيسبيك كان أيضًا مصدرًا رائعًا، لأنهم قاموا بتوثيق الوظيفة بدقة.
هذا صحيح.
خلف الكواليس، التضمين هو في الواقع اسم مستعار لـ append_features, ، والتي (من المستندات):
يتمثل تطبيق Ruby الافتراضي في إضافة الثوابت والأساليب ومتغيرات الوحدة النمطية لهذه الوحدة إلى Amodule إذا لم تتم إضافة هذه الوحدة بالفعل إلى Amodule أو أحد أسلافه.
جميع الإجابات الأخرى جيدة، بما في ذلك نصيحة البحث في RubySpecs:
https://github.com/rubyspec/rubyspec/blob/master/core/module/include_spec.rb
https://github.com/rubyspec/rubyspec/blob/master/core/module/extend_object_spec.rb
أما بالنسبة لحالات الاستخدام:
اذا أنت يشمل الوحدة النمطية ReusableModule في فئة ClassThatIncludes، تتم الإشارة إلى الأساليب والثوابت والفئات والوحدات الفرعية والإعلانات الأخرى.
اذا أنت يمتد فئة ClassThatExtends مع الوحدة النمطية ReusableModule، ثم يتم الحصول على الأساليب والثوابت نسخ.من الواضح، إذا لم تكن حذرًا، يمكنك إضاعة الكثير من الذاكرة عن طريق تكرار التعريفات ديناميكيًا.
إذا كنت تستخدم ActiveSupport::Concern، فإن وظيفة .included() تتيح لك إعادة كتابة فئة التضمين مباشرة.تحصل الوحدة النمطية ClassMethods داخل القلق ممتد (منسوخ) في الفئة بما في ذلك.
وأود أيضًا أن أشرح الآلية أثناء عملها.إذا لم أكن على حق يرجى التصحيح.
عندما نستخدم include
نحن نضيف رابطًا من فصلنا إلى وحدة تحتوي على بعض الأساليب.
class A
include MyMOd
end
a = A.new
a.some_method
لا تحتوي الكائنات على طرق، بل هناك فئات ووحدات نمطية فقط.اذن متى a
يتلقى الرسالة some_method
تبدأ طريقة البحث some_method
في a
فئة eigen، ثم في A
فئة ومن ثم في مرتبطة ب A
وحدات الفصل الدراسي إذا كان هناك بعض منها (بترتيب عكسي، يفوز آخر ما تم تضمينه).
عندما نستخدم extend
نحن نضيف ارتباطًا بوحدة نمطية في فئة الكائن الذاتية.لذا، إذا استخدمنا A.new.extend(MyMod) فإننا نضيف رابطًا إلى وحدتنا إلى فئة eigen لمثيل A أو a'
فصل.وإذا استخدمنا A.extend(MyMod) فإننا نضيف ارتباطًا إلى A(object's,classes هي أيضًا كائنات) eigenclass A'
.
لذلك مسار البحث عن الأسلوب a
على النحو التالي:a => a' => الوحدات المرتبطة بـ' class => A.
هناك أيضًا طريقة ملحقة تغير مسار البحث:
a => a' => الوحدات النمطية المسبقة إلى A => A => الوحدة النمطية المضمنة في A
اسف على سوء لغتي الانجليزية.