Menu
CoddyTech

الكتابة بأسلوب البطة

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

لا يتحقق Ruby من فئة الكائن قبل استدعاء طريقة؛ بل يحتاج فقط إلى أن تكون لدى الكائن الطريقة. «إذا كان يمشي كالبطة ويُصدر صوتًا كالبطة، فهو بطة». هذا هو التصنيف بأسلوب البطة: يمكن استخدام الفئات التي لا تشترك في أي فئة فائقة في الموضع نفسه:

class Duck
  def speak
    "Quack"
  end
end

class Robot
  def speak
    "Beep"
  end
end

class Radio
  def speak
    "...news..."
  end
end

[Duck.new, Robot.new, Radio.new].each { |thing| puts thing.speak }

الناتج:

Quack
Beep
...news...

تشارك الأصناف المضمّنة أيضًا. تعمل الطريقة التي تستخدم << فقط مع مصفوفة أو سلسلة نصية أو أي كائن خاص بك يعرّف <<:

class Tally
  attr_reader :count

  def initialize
    @count = 0
  end

  def <<(_item)
    @count += 1
    self
  end
end

def export(items, target)
  items.each { |item| target << item.to_s }
  target
end

p export([1, 2], [])
p export([1, 2], +"")
puts export([1, 2, 3], Tally.new).count

الناتج:

["1", "2"]
"12"
3

يسأل respond_to?(:name) عمّا إذا كان للكائن أسلوب عام، دون استدعائه. استخدمه عندما يُحتمل أن يدعم الكائن ميزة اختيارية أو لا يدعمها:

class Printer
  def print_page(text)
    "printing #{text}"
  end
end

class Scanner
end

[Printer.new, Scanner.new].each do |device|
  if device.respond_to?(:print_page)
    puts device.print_page("report")
  else
    puts "#{device.class} cannot print"
  end
end

الناتج:

printing report
Scanner cannot print

عندما لا يحتوي الكائن على الطريقة، يؤدي استدعاؤها إلى رفع NoMethodError، وتذكر رسالتها اسم الطريقة والكائن. يعتمد التنميط البَطّي على أن يستجيب كل كائن يُمرَّر إلى الطريقة للطرق التي تُستدعى عليه:

def loudest(things)
  things.map(&:speak).max_by(&:size)
end

class Cat
  def speak
    "Meow"
  end
end

puts loudest([Cat.new, Cat.new])
begin
  loudest([Cat.new, 42])
rescue NoMethodError => e
  puts e.message
end

الناتج:

Meow
undefined method `speak' for an instance of Integer
challenge icon

التحدي

سهل

أكمل الصنفين Printer وLineCounter والمساعد export(items, target) في functions.rb. ترسل export كل عنصر إلى الهدف باستخدام target << item.to_s وتُعيد الهدف. تعرض Printer#<< النص مع رقم السطر، 1: text، وتُعيد الطابعة. تحسب LineCounter#<< الأسطر والأحرف وتُعيد العداد؛ وتُعيد to_s القيمة 3 lines, 12 chars.

تقرأ الشيفرة المقدمة العناصر، وتُصدّرها إلى مصفوفة (تُطبع باستخدام p)، وإلى سلسلة جديدة (تُطبع باستخدام p)، وإلى Printer وإلى LineCounter (تُطبع باستخدام puts).

ضع شيفرتك في printer.rb وline_counter.rb وfunctions.rb. يحتوي main.rb على شيفرة الإدخال/الإخراج المقدمة ولا يمكن تعديله.

جرّب بنفسك

require_relative 'printer'
require_relative 'line_counter'
require_relative 'functions'

# شيفرة الإدخال/الإخراج المقدَّمة: أبقِها كما هي
input = []
while (line = gets)
  input << line.chomp
end
p export(input, [])
p export(input, +"")
export(input, Printer.new)
puts export(input, LineCounter.new)
quiz iconاختبر نفسك

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

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

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