المعيّنات الخاصة
جزء من قسم البرمجة كائنية التوجه في رحلة Ruby على Coddy. الدرس 19 من 57.
غالبًا ما ينبغي أن تكون القيمة قابلة للقراءة من الجميع، لكن لا يمكن تغييرها إلا بواسطة الكائن. يوفّر attr_reader قارئًا عامًا، بينما يوفّر private attr_writer أداة ضبط لا يمكن استخدامها إلا بواسطة الكائن. ينجح هذا لأن attr_writer يعيد أسماء الطرق التي يعرّفها:
class Wallet
attr_reader :balance
def initialize
self.balance = 0
end
def earn(amount)
self.balance = balance + amount
end
private attr_writer :balance
end
w = Wallet.new
w.earn(30)
puts w.balance
begin
w.balance = 1_000_000
rescue NoMethodError => e
puts e.message
endالناتج:
30
private method `balance=' called for an instance of Walletيُستدعى المُعيِّن الخاص باستخدام self. داخل الصنف، وهو المُستقبِل الوحيد الذي يقبله Ruby للطرائق الخاصة. من دون self.، لن يُنشئ الإسناد سوى متغيّر محلي:
class Lamp
attr_reader :on
def initialize
self.on = false
end
def toggle
self.on = !on
self
end
private
attr_writer :on
end
puts Lamp.new.toggle.toggle.toggle.onالناتج:
trueإن استخدام مُعيِّن خاص بدلًا من إسناد قيمة إلى @balance مباشرةً يُبقي القواعد في مكان واحد، مثل التحقق من صلاحية القيمة:
class Tank
attr_reader :litres
def initialize(capacity)
@capacity = capacity
self.litres = 0
end
def fill(amount)
self.litres = litres + amount
end
def drain(amount)
self.litres = litres - amount
end
private
def litres=(value)
@litres = value.clamp(0, @capacity)
end
end
t = Tank.new(50)
t.fill(80)
puts t.litres
t.drain(70)
puts t.litresالناتج:
50
0يُخفي private attr_accessor :history كلاً من القارئ والمُعيِّن، وذلك للحالة الداخلية التي لا ينبغي حتى للكود الخارجي الاطّلاع عليها:
class Editor
def initialize
self.history = []
end
def type(text)
history << text
end
private attr_accessor :history
endالتحدي
سهلأكمل الصنف Wallet. يمكن قراءة balance من الخارج، لكن لا يمكن تعيينها إلا عبر أداة تعيين خاصة، وتبدأ قيمتها عند 0. تضيف earn(amount) المقدار إليها. تطرح spend(amount) المقدار وتُرجع true، أو تُرجع false دون إجراء أي تغيير عندما يكون الرصيد منخفضًا جدًا. تُرجع history عدد التغييرات الناجحة، وهي أيضًا محمية بأداة تعيين خاصة.
يقرأ الكود المرفق الأوامر +n أو -n، ويطبع balance 30 بعد كل أمر، أو declined عند فشل عملية الإنفاق. ثم يطبع changes: 2 ويحاول تنفيذ wallet.balance = 1000000، ويطبع cannot set balance عندما يرفض Ruby ذلك.
ضع الكود في wallet.rb. يحتوي main.rb على كود الإدخال والإخراج المرفق، ولا يمكن تعديله.
جرّب بنفسك
require_relative 'wallet'
# شيفرة الإدخال/الإخراج المقدَّمة: اتركها كما هي
input = []
while (line = gets)
input << line.chomp
end
wallet = Wallet.new
input.each do |cmd|
amount = cmd[1..].to_i
if cmd.start_with?("+")
wallet.earn(amount)
puts "balance #{wallet.balance}"
elsif wallet.spend(amount)
puts "balance #{wallet.balance}"
else
puts "declined"
end
end
puts "changes: #{wallet.history}"
begin
wallet.balance = 1_000_000
puts "balance set"
rescue NoMethodError
puts "cannot set balance"
end
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1الفئات والكائنات
العمل مع الملفاتتعريف الفئاتمتغيرات النسخةالأساليب و selfto_s و inspectمراجعة - بطاقة المكتبة7تعدد الأشكال والكتابة بأسلوب البطة
تعدد الأشكالالكتابة بأسلوب البطةالأساليب المجردةالحالات والفئاتمراجعة - طرق الدفع3أساليب ومتغيرات الأصناف
أساليب الأصنافمتغيرات كائنات الأصنافالثوابتأساليب الإنشاءمراجعة - رموز القسائمتدرّب بنفسك: مترجم Ruby عبر الإنترنت