プロテクトメソッド
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 Accountprivateとの違いは、レシーバーが別のオブジェクトの場合に現れます。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 とも連携します。これは、たとえば2つのオブジェクトのどちらが勝つかを決めるために、通常、1つのクラスのオブジェクト間だけで値を共有する方法です:
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オンラインコンパイラ