はじめに
アクセス修飾子のprivateについての基本的な解説です。
var, let, constのように特徴やメリットがあり、開発の品質にも直接関わってくるものですのでしっかりと用途を考えて使えるように改めてまとめました。
privateはクラス外からアクセスできない
Rubyの源流であるオブジェクト指向の三大原則の一つ「カプセル化」は、あるクラスの変数やメソッドを他のオブジェクトから呼び出せないようにする考え方です。
これにより必要のない変更操作などを防ぐ安全性が担保できます。
Rubyにおいてprivateアクセス修飾子のついた(また修飾子以降に書かれた)メソッドは全てクラスの外からアクセスができなくなります。
クラスの中から呼び出される形でのみ使用することができます。
class House
private def getAsset
# 財産を手に入れるメソッド
end
end
外からアクセスできないメソッドを定義する理由はなんなのか?
理解していないうちはprivateなんていらないかと思う人もいますが、privateはセキュリティの観点から見て必要不可欠な機能です。
もしアクセスできる領域が限定されているべきなのに限定されていない値があったとしたら、例えば以下のようなことが想定できます。
- 銀行口座インスタンスの残高を外部から自由に書き換えできる
- RPGにおいてキャラクタインスタンスのステータスを外部から好き勝手に書き換えられる
- ActionModelクラスの属性を、正規の手順を踏まずに好き勝手書き換えられる
- あるユーザがSNSで他ユーザのパスワードをのぞき見できる
いずれも非常に危険で、アプリケーションの存続が危ぶまれるケースです。
追記
privateについて
カプセル化を実現した代表的な言語であるJava等と違い、Rubyにおけるアクセス修飾子は以下のような挙動をします。
Rubyリファレンスマニュアルによると、privateは以下のようにあります。
「private に設定されたメソッドは関数形式でしか呼び出せません。」
つまりインスタンス.privateメソッド
の形式では呼ぶことができないということですね。
このときメソッドを呼び出されるインスタンスのことを、「“メソッドを実行しろ“というメッセージを受け取っている対象」と解釈して「レシーバ」と呼んだりします。
クラス内で直接privateメソッドを呼び出すことができるけれども、レシーバ形式での呼び出しが不可能になります。
class A
def call_private
private_method # 関数形式での呼び出し(できる)
end
def call_private_with_reciever
self.private_method # レシーバ(self)形式での呼び出し(できない)
end
private
def private_method
p "只今privateメソッドテスト中!"
end
end
a = A.new
a.call_private #呼び出せます
a.call_private_with_reciever #エラーになります
また、呼び出そうと思えばクラスの外からもsendメソッドでprivateなメソッドを呼び出せてしまいます。
よって、Rubyのアクセス修飾子は厳密なカプセル化を実現する目的とはまた違うみたいですね。
a.send(:private_method) # 呼び出せます
※やろうと思えばKernel#exitを呼び出して、アプリケーションを強制終了させることも外部から可能になってしまうので、外部から引数として変数名を入力させるアプリケーションは大変危険ですので実装すべきではないです。
protectedについて
また、protectedについてはリファレンスによるとこうあります。
「protected に設定されたメソッドは、そのメソッドを持つオブジェクトが selfであるコンテキスト(メソッド定義式やinstance_eval)でのみ呼び出せます。」
つまり、同一クラス(および継承先クラス)からならレシーバ形式self.protectedメソッド
でも呼び出せるということですね。
class Sample
def == other #==の処理を独自に更新しようとしています。Rubyでは==をはじめ全ての演算子が関数オブジェクトとして扱えるので、このような更新が可能です。
if self.class == other.class
internal == other.internal
else
super
end
end
protected
def internal; :sample; end
end
Sample.new == Sample.new #=> true
まとめ
privateの重要性は現実世界では大切なものを守るとき、例えば家に置いてある財産を泥棒に取られないようにするために「家の出入り口に鍵をかける」ことと考え方は同じです。
「大切なものに対するアクセスは得てして不自由である方が扱いやすい」のです。
参考
この記事は「CodeShip」内での実際の質疑応答や指導・アドバイスの一部を基に作成しています。