【今日のQ&A】privateの用途・メリット【アクセス修飾子】

こんにちは、@codeship_techです。

今回はアクセス修飾子のprivateについての解説です!

var, let, constのように特徴やメリットがあり、開発の品質にも直接関わってくるものですのでしっかりと用途を考えて使えるようにしましょう!

privateって何ですか?

アクセス修飾子の一つです。
クラス外からはアクセスできない」ことを意味しています。

Rubyの源流であるオブジェクト指向の三大原則の一つ「カプセル化」は、あるクラスの変数やメソッドを他のオブジェクトから呼び出せないようにする考え方です。

これにより必要のない変更操作などを防ぐ安全性が担保できます。

Rubyにおいてprivateアクセス修飾子のついた(また修飾子以降に書かれた)メソッドは全てクラスの外からアクセスができなくなります。
クラスの中から呼び出される形でのみ使用することができます。

ruby
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を呼び出して、アプリケーションを強制終了させることも外部から可能になってしまうので、外部から引数として変数名を入力させるアプリケーションは大変危険ですので実装すべきではないです。

授業日記についてのご意見

CodeShipの授業について「こんな事が知りたい・紹介して」というご意見・ご提案がありましたら、CodeShip公式Twitterアカウント(【CodeShip】プログラミングスクール)までDMまたはリプライにてお寄せください。