プロテクトメソッド
CoddyのRubyジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 18/57。
protected メソッドは public と private の中間に位置します。外部のコードから呼び出すことはできませんが、同じクラスのオブジェクトなら、別のオブジェクトに対して呼び出すことができます。これにより、2つのオブジェクトはプログラムのほかの部分には公開しないデータを比較できます。
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はprotectedメソッドでは動作しますが、privateメソッドでは失敗します:
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.hiddenprotectedは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 # そのクラスのオブジェクト: Account 内の other.balance
private # そのオブジェクト自身のみ: subtotal, self.subtotalチャレンジ
簡単クラス Account を完成させてください。残高は他のアカウントからのみ読み取れるようにします。読み取りメソッドを protected にしてください。richer_than?(other) は残高を比較し、transfer_to(other, amount) は相手のアカウントの protected メソッド receive(amount) を通じて別のアカウントにお金を移し、true を返します。残高が不足している場合は false を返します。to_s は所有者の名前だけを返します。
提供されたコードは2人の所有者と残高を読み取り、その後 transfer a b 50 コマンドを処理して、ok または refused を出力します。続いて Ada is richer(または Bo is richer、または equal)を出力し、最後に外部から balance を読み取ろうとし、Ruby が拒否した場合は balance is protected を出力します。
コードは 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
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rubyオンラインコンパイラ