ruby のpublic、private、および protectedの定義を読むと役立つ場合があります。(アクセス制御にスキップ)
Ruby の private は、Java の protected に似ています。Java のプライベートに相当する Ruby はありません。編集:このソリューションは、Ruby オブジェクトで Java のプライベートの理想を偽装する方法を提供するようになりました。
Private は、暗黙的にのみ呼び出すことができるメソッド/変数として定義されています。これが、ステートメント 2 と 3 が失敗する理由です。つまり、private は、メソッド/変数を、それらが定義されているクラスまたはサブクラスのコンテキストに制限します。継承は、プライベート メソッドをサブクラスに渡すため、暗黙的な自己でアクセスできます。(ステートメント6が機能する理由を説明しています。)
保護されたものに近いものを探していると思います。可視性が与えられていない Java アクセサー (例: public、private、protected) と同様に動作します。Spy の private を protected に変更すると、6 つのステートメントすべてが機能します。保護されたメソッドは、定義クラスまたはそのサブクラスの任意のインスタンスから呼び出すことができます。呼び出し元が呼び出しに応答するオブジェクトのクラスであるか、それから継承されている限り、self で明示的または暗黙的に呼び出されたものは、保護されたメソッドの有効なステートメントです。
class Person
private
attr_reader :weight
end
class Spy < Person
protected
attr_accessor :code
public
def test
code #(1) OK: you can call a private method in self
Spy.new.code #(2) OK: Calling protected method on another instance from same class family or a descendant.
self.code #(3) OK: Calling protected method on with explicit self is allowed with protected
code="xyz" #(4) Ok, it runs, but it actually creates a local variable!!!
self.code="z" #(5) OK! This is the only case where explicit 'self' is ok
weight #(6) OK! You can call a private method defined in a base class
end
end
s = Spy.new
s.test # succeeds
s.code #(7) Error: Calling protected method outside of the class or its descendants.
ステートメント 4 については、あいまいさを避けるためであると仮定して正しいです。これは、Ruby の動的な性質の潜在的な害に対する安全策です。後でクラスを再度開いてアクセサーをオーバーライドできないようにします。たとえば、汚染されたコードを評価することによって発生する可能性のある状況。
これらの動作につながった彼の設計上の決定については推測することしかできません。そのほとんどは、言語の動的な性質に帰着すると思います。
PS本当に物事にプライベートのJava定義を与えたい場合。サブクラスではなく、定義されているクラスでのみ使用できます。クラスに self.inherited メソッドを追加して、アクセスを制限したいメソッドへの参照を削除できます。
サブクラスから weight 属性にアクセスできないようにする:
class Person
private
attr_reader :weight
def initialize
@weight = 5
end
def self.inherited(subclass)
subclass.send :undef_method, :weight
end
end
class Spy < Person
private
attr_accessor :code
public
def test
weight
end
end
Person.new.send(:weight) # => 5
Spy.new.send(:weight) #=> Unhelpful undefined method error
undef_method 呼び出しを次のように置き換える方が理にかなっているかもしれません:
def self.inherited(subclass)
subclass.class_eval %{
def weight
raise "Private method called from subclass. Access Denied"
end
}
end
これにより、はるかに役立つエラーと同じ機能が提供されます。
send は、他のクラスのプライベート メソッドの呼び出しを回避するために必要です。物事が実際に機能していることを証明するためにのみ使用されます。
後から考えると、これは非公開で保護されたものを役に立たなくします。メソッドの保護に真剣に取り組んでいる場合は、send をオーバーライドしてメソッドをブロックする必要があります。次のコードは、オブジェクトの private_methods に基づいてそれを行います。
def send_that_blocks_private_methods(method, *args)
if private_methods.include?(method.to_s)
raise "Private method #{method} cannot called be called with send."
else
send_that_allows_private_methods(method, *args)
end
end
alias_method :send_that_allows_private_methods, :send
alias_method :send, :send_that_blocks_private_methods
private :send_that_allows_private_methods
すべてのプライベート メソッドへのアクセスを拒否する代わりに、アクセスをブロックする private_methods の class_variable を指定できます。send を非公開にすることもできますが、オブジェクトの外部から send を呼び出す正当な用途があります。