Phương thức thiết lập riêng tư
Thuộc phần Lập trình hướng đối tượng trong hành trình Ruby của Coddy. Bài học 19 trên 57.
Thường thì mọi người nên đọc được một giá trị, nhưng chỉ đối tượng mới có thể thay đổi giá trị đó. attr_reader tạo phương thức đọc công khai, còn private attr_writer tạo phương thức gán mà chỉ đối tượng mới có thể dùng. Cách này hoạt động vì attr_writer trả về tên các phương thức mà nó định nghĩa:
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Đầu ra:
30
private method `balance=' called for an instance of WalletBạn gọi setter riêng tư bằng self. bên trong lớp, đây là đối tượng nhận duy nhất mà Ruby chấp nhận cho phương thức riêng tư. Nếu không có self., phép gán chỉ tạo một biến cục bộ:
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Đầu ra:
trueĐi qua setter riêng tư thay vì gán trực tiếp @balance giúp tập trung các quy tắc ở một nơi, chẳng hạn như kiểm tra giá trị có hợp lệ hay không:
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Đầu ra:
50
0private attr_accessor :history ẩn cả phương thức đọc lẫn phương thức thiết lập, dành cho trạng thái nội bộ mà code bên ngoài thậm chí không nên nhìn thấy:
class Editor
def initialize
self.history = []
end
def type(text)
history << text
end
private attr_accessor :history
endThử thách
DễHoàn thiện lớp Wallet. Có thể đọc balance từ bên ngoài nhưng chỉ có thể gán giá trị thông qua setter riêng tư, bắt đầu từ 0. earn(amount) cộng thêm vào giá trị này. spend(amount) trừ đi và trả về true, hoặc trả về false mà không thay đổi gì khi số dư quá thấp. history trả về số lần thay đổi thành công, và cũng được bảo vệ bằng setter riêng tư.
Code được cung cấp đọc các lệnh +n hoặc -n, in ra balance 30 sau mỗi lệnh, hoặc declined khi thao tác chi tiêu thất bại. Sau đó, code in ra changes: 2 và thử wallet.balance = 1000000, in ra cannot set balance khi Ruby từ chối.
Đặt code của bạn trong wallet.rb. main.rb chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.
Tự làm thử
require_relative 'wallet'
# Đoạn code đầu vào/đầu ra đã có sẵn: giữ nguyên
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
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Lớp và đối tượng
Làm việc với tệpĐịnh nghĩa lớpBiến instancePhương thức và selfto_s và inspectÔn tập: thẻ thư viện4Tính đóng gói
Phương thức riêng tưPhương thức được bảo vệPhương thức thiết lập riêng tưBảo vệ trạng tháiÔn tập: máy bán hàng tự động7Tính đa hình và duck typing
Tính đa hìnhDuck typingPhương thức trừu tượngcase và lớpÔn tập: phương thức thanh toán2Phương thức truy cập và self
Phương thức đọc và ghiPhương thức gán tùy chỉnhself trong phương thứcĐịnh danh và tính bằng nhauÔn tập: Danh sách liên hệTự luyện tập: Trình biên dịch Ruby online