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

الأساليب المحمية

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

تقع الطريقة protected بين public وprivate. لا يمكن للكود الخارجي استدعاؤها، لكن يمكن لأي كائن من الفئة نفسها استدعاؤها على كائن آخر منها. يتيح ذلك لكائنين مقارنة بيانات لا يعرضانها لبقية البرنامج:

class Account
  def initialize(owner, balance)
    @owner = owner
    @balance = balance
  end

  def richer_than?(other)
    balance > other.balance
  end

  protected

  def balance
    @balance
  end
end

ada = Account.new("Ada", 500)
bo = Account.new("Bo", 300)
puts ada.richer_than?(bo)
begin
  ada.balance
rescue NoMethodError => e
  puts e.message
end

المخرجات:

true
protected method `balance' called for an instance of Account

يظهر الفرق عن private عندما يكون المستقبل كائنًا آخر. يعمل other.balance مع طريقة محمية ويفشل مع طريقة خاصة:

class Sample
  def initialize(n)
    @n = n
  end

  def compare_protected(other)
    other.guarded + guarded
  end

  def compare_private(other)
    other.hidden + hidden
  rescue NoMethodError
    "private refused other.hidden"
  end

  protected

  def guarded
    @n
  end

  private

  def hidden
    @n
  end
end

a = Sample.new(1)
b = Sample.new(2)
puts a.compare_protected(b)
puts a.compare_private(b)

الناتج:

3
private refused other.hidden

تعمل protected أيضًا مع attr_reader، وهي الطريقة المعتادة لمشاركة قيمة بين كائنات فئة واحدة فقط، مثلًا لتحديد أيّ كائنين يفوز:

class Player
  attr_reader :name

  def initialize(name, rating)
    @name = name
    @rating = rating
  end

  def stronger?(other)
    rating > other.rating
  end

  protected

  attr_reader :rating
end

a = Player.new("Ada", 1200)
b = Player.new("Bo", 1100)
puts a.stronger?(b)
puts [a, b].select { |pl| pl.stronger?(b) }.map(&:name).inspect

الناتج:

true
["Ada"]

اختر أضيق مستوى ينجح. public لواجهة الصنف، وprotected للبيانات التي تقارنها كائنات الصنف مع بعضها، وprivate لكل ما عدا ذلك:

public      # أي شخص: order.total
protected   # كائنات الصنف: other.balance داخل Account
private     # الكائن نفسه فقط: subtotal, self.subtotal
challenge icon

التحدي

سهل

أكمل الصنف Account. لا يمكن قراءة الرصيد إلا من قِبل الحسابات الأخرى: اجعل قارئه محميًا. تقارن richer_than?(other) الأرصدة، وتنقل transfer_to(other, amount) المال إلى حساب آخر من خلال الطريقة المحمية receive(amount) الخاصة بالحساب الآخر، وتُرجع true، أو تُرجع false عندما يكون الرصيد منخفضًا جدًا. تُرجع to_s اسم المالك فقط.

يقرأ الكود المزوَّد اسمي المالكين ورصيديهما، ثم أوامر transfer a b 50، ويطبع ok أو refused. ثم يطبع Ada is richer (أو Bo is richer، أو equal) ويحاول أخيرًا قراءة balance من الخارج، ويطبع balance is protected عندما يرفض Ruby ذلك.

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

جرّب بنفسك

require_relative 'account'

# كود الإدخال/الإخراج المُزوَّد: أبقِه كما هو
input = []
while (line = gets)
  input << line.chomp
end
accounts = input[0..1].map do |line|
  owner, balance = line.split
  Account.new(owner, balance.to_i)
end
a, b = accounts
input.drop(2).each do |line|
  _, from, to, amount = line.split
  source = from == "a" ? a : b
  target = to == "a" ? a : b
  puts source.transfer_to(target, amount.to_i) ? "ok" : "refused"
end
if a.richer_than?(b) then puts "#{a} is richer"
elsif b.richer_than?(a) then puts "#{b} is richer"
else puts "equal"
end
begin
  a.balance
  puts "balance is public"
rescue NoMethodError
  puts "balance is protected"
end
quiz iconاختبر نفسك

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

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

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