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

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

جزء من قسم البرمجة كائنية التوجه في رحلة 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 عبر الإنترنت