Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

توسيع الكائنات

جزء من قسم البرمجة كائنية التوجه في رحلة Ruby على Coddy. الدرس 28 من 57.

تضيف extend أساليب الوحدة إلى كائن واحد بدلًا من إضافتها إلى جميع النسخ. تؤدي إضافة الامتداد إلى فئة إلى إضافة الأساليب إلى كائن الفئة، ولذلك تصبح أساليب فئة:

module Describable
  def describe
    "#{name} has #{instance_methods(false).size} methods"
  end
end

class Dog
  extend Describable

  def bark
    "Woof"
  end

  def sit
    "sits"
  end
end

puts Dog.describe

الناتج:

Dog has 2 methods

يمكن لوحدة مستخدمة مع extend أن تحتفظ بالحالة في متغيرات مثيلات الصنف. ويحصل كل صنف يمددها على نسخة خاصة به، بوصفها متغيرات مثيلات الصنف:

module Counted
  def created
    @created ||= 0
  end

  def record
    @created = created + 1
  end
end

class Order
  extend Counted
end

class Invoice
  extend Counted
end

Order.record
Order.record
Invoice.record
puts "#{Order.created} #{Invoice.created}"

الناتج:

2 1

تعمل extend أيضًا على كائن واحد. يكتسب ذلك الكائن وحده الأساليب؛ وتبقى النسخ الأخرى من فئته دون تغيير، وتكون is_a? هي true للكائن المُوسَّع فقط:

module Shiny
  def polish
    "#{self} is shining"
  end
end

a = "car"
b = "bike"
a.extend(Shiny)
puts a.polish
puts a.is_a?(Shiny)
puts b.respond_to?(:polish)

المخرجات:

car is shining
true
false

تضع الكلمتان المفتاحيتان أساليب الوحدة نفسها في أماكن مختلفة. تجعل include هذه الأساليب أساليبَ مثيلات لفئة، بينما تجعل extend منها أساليبَ للكائن الواحد الذي يتم توسيعه:

class Order
  include Printable    # order.print_me       (كل مثيل)
  extend Counted       # Order.record         (الصنف نفسه)
end

item.extend(Shiny)     # item.polish          (هذا الكائن فقط)
challenge icon

التحدي

سهل

أكمل الوحدة البرمجية Registry التي تستخدمها الأصناف مع extend. تضيف register(name) اسمًا إلى القائمة الخاصة بالصنف، المحفوظة في @entries (والتي تُنشأ عند أول استخدام)، وتُرجع Plugin registered x؛ أما الاسم الموجود مسبقًا فتُرجع له Plugin already has x. تُرجع entries القائمة، بينما تُرجع count حجمها. يعمل كل من Plugin وTheme على توسيع Registry ويحتفظ كل منهما بقائمة منفصلة.

يقرأ الكود المزوَّد أسطرًا بالصيغة plugin name أو theme name، ويستدعي register على الصنف المطابق ثم يطبع الرد. وأخيرًا يطبع plugins: a, b (2) وthemes: ...، أو none (0) للقائمة الفارغة.

ضع كودك في registry.rb وplugin.rb وtheme.rb. يحتوي main.rb على كود الإدخال/الإخراج المزوَّد، ولا يمكن تعديله.

جرّب بنفسك

require_relative 'registry'
require_relative 'plugin'
require_relative 'theme'

# كود الإدخال/الإخراج المُزوَّد: أبقِه كما هو
input = []
while (line = gets)
  input << line.chomp
end
input.each do |line|
  kind, name = line.split
  target = kind == "plugin" ? Plugin : Theme
  puts target.register(name)
end
[["plugins", Plugin], ["themes", Theme]].each do |label, klass|
  list = klass.entries.empty? ? "none" : klass.entries.join(", ")
  puts "#{label}: #{list} (#{klass.count})"
end
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم Ruby عبر الإنترنت