Rubyのprivateメソッドとprotectedメソッドを徹底解説!メソッドの可視性をマスターしよう
Rubyにおける「プライベートメソッド」とは、そのメソッドが定義されたクラスの内部からしか呼び出せないメソッドのことです。
privateやprotectedといった可視性(visibility)を適切に設定することで、クラス外部からのアクセスを制御し、より安全で保守しやすいコードを書くことができます。
Rubyの3つのメソッド可視性
Rubyのメソッドには、以下の3種類の可視性があります。
- private … クラス内部からのみ呼び出せる
- public … デフォルト。誰でも呼び出せる
- protected … クラス内部+同クラスのインスタンス経由で呼び出せる
デフォルトでは、すべてのメソッドはpublicになります。つまり、何も指定しなければ誰でもそのメソッドを使える状態です。
しかし、privateやprotectedを指定することで、この挙動を変更できます。
なぜ可視性の制御が重要なのか?
publicメソッドを減らすことで、クラス内部を自由に変更できる余地が広がるからです。
具体例を挙げてみましょう。あなたが職場で複数のプロジェクトから利用されるライブラリを開発しているとします。各プロジェクトは、あなたが作成したクラスのメソッドを呼び出して使うことになります。
ここで新しいバージョンをリリースする際に、あるpublicメソッドの名前を変更したらどうなるでしょうか?
答えは簡単です。そのメソッドを利用しているすべてのプロジェクトでエラーが発生してしまいます。
逆に言えば、publicメソッドの数を最小限に抑えておけば、クラスの内部実装は自由にリファクタリングできるのです。これがメソッドの可視性を意識する最大の理由です。
それでは、実際のコード例を見ていきましょう。
Rubyのprivateメソッドを理解する
「private method called」というエラーメッセージを見たことはありませんか?
self.puts 123 # NoMethodError: private method `puts' called
これは、privateメソッドを誤った形式で呼び出そうとしたときに発生するエラーです。
privateメソッドはレシーバを明示せず、単体で呼び出す必要があります。
puts 123
同じメソッドでも、このように呼び出せば正常に動作します。
privateメソッドは常にselfのコンテキスト内で呼び出されるため、次のような場合にのみ使用できます。
- 同じクラス内の他のメソッドから
- 親クラスから継承したメソッドから
- モジュールからincludeしたメソッドから
つまり、privateメソッドは定義されたクラスの外部からは呼び出せません。外部から呼び出すには「明示的なレシーバ」が必要になるためです。
ただし、例外的な手段として、sendメソッドを使えばこのルールを回避できます。
send(:puts, "apple")
では、privateメソッドはどうやって定義するのでしょうか?
def bacon "private bacon" end private :bacon
実はprivateという言葉自体はキーワードではなく、Kernelモジュールで定義されたメソッドなのです。
privateメソッドはどこに書くべき?
1つのクラスが複数のprivateメソッドを持つのはごく普通のことです。では、これらのメソッドはどこに配置すればよいのでしょうか?
おすすめの書き方はこちらです。
class Food def public_method end private def bacon end def orange end def coconut end end
private以降に定義されたすべてのインスタンスメソッドは、自動的にprivateメソッドになります。
クラスメソッドをprivateにしたい場合は、
private_class_method :メソッド名を使用します。
実務では「publicメソッドを先に定義し、private以下にまとめてprivateメソッドを配置する」というパターンが一般的です。コードの可読性も大きく向上します。
publicメソッドとは
publicはRubyにおけるデフォルトのメソッド可視性です。
def orange "Vitamin C" end
orangeメソッドを持つオブジェクトfoodがあれば、次のように呼び出せます。
food.orange
また、一度privateやprotectedに変更したメソッドも、再度publicに戻すことができます。
public :orange
protectedメソッドとは何か?
protectedメソッドは、privateメソッドほど頻繁に使われるものではありません。
protectedはprivateと似ていますが、「同じクラス(またはサブクラス)の他のインスタンスに対して、レシーバを明示して呼び出せる」という点が異なります。
もし上記の例をprivateで試すとエラーになります。
class Food
def initialize(name)
@name = name
end
def ==(other)
name == other.name
end
protected
attr_reader :name
end
food = Food.new("chocolate")
puts food == food
nameがprivateだと、other.nameという形で呼び出せないためエラーが発生します。
しかしprotectedであれば、このコードは正常に動作するのです。
privateとprotectedの違いとは?
まとめると、protectedはメソッドをクラス外から隠しつつ、同一クラスのインスタンスに対してはレシーバ付きで呼び出せるという違いがあります。
- privateの場合:
nameのみ呼び出し可能 - protectedの場合:
object.nameの形式でも呼び出し可能
では、protectedはいつ使うべきなのでしょうか?
基本的には、等価比較(==)メソッドのように、同クラスの別インスタンスの内部状態を比較する必要がある、非常に限られたケースだけです。
Rubyの公式ドキュメントでも、可能な限りprivateを使うことが推奨されています。
さらに、ドキュメントにはこんな注記もあります。
「protectedメソッドはインラインキャッシュを利用できないため、遅くなる。」
気になったので、実際にベンチマークを実行してみました。
public: 2813891.9 i/s private: 2699273.8 i/s protected: 2572122.0 i/s
結果として、protectedはpublicと比べて約8.5%性能が劣ることがわかりました。パフォーマンス面でも、privateを優先する理由があると言えます。
動画チュートリアル
記事だけでなく、動画でも学習したい方のために解説動画をご用意しています。
まとめ
今回はRubyのメソッド可視性について、public・private・protectedの3種類を学びました。
重要なポイントをおさらいしましょう。
- private:クラス内部からのみ、レシーバなしで呼び出せる
- public:デフォルト。どこからでも呼び出せる
- protected:同クラスのインスタンスに対してはレシーバ付きで呼び出せるが、やや遅い
そして忘れてはならないのが、privateやprotectedはRubyのキーワードではなく、Moduleクラスで定義されたメソッドだという点です。
publicメソッドを絞り込むことでクラスの保守性は大きく向上します。ぜひ日々のコーディングに活かしてください。
この記事が役に立ったら、ぜひ周りの方にもシェアしてくださいね。
最後まで読んでいただきありがとうございました 🙂
-
Rubyのメソッド入門:defキーワードで独自のメソッドを定義する方法
Rubyにおける「メソッド」とは、特定の目的のためにひとまとめにされた、1行以上のRubyコードのことです。 このコードのまとまりには名前が付けられており、一度定義してしまえば、同じコードを何度も書いたりコピー&ペーストしたりすることなく、必要なときにいつでも再利用できます。 メソッドの主な役割 メソッドの目的は、大きく分けて以下のようなものがあります。 情報を取得する オブジェクトを変更・生成する データをフィルタリング・整形する 具体例 例1: Arrayオブジェクトに対するsizeメソッドは、配列内の要素数を返します(情報の取得)。 例2: popメソッドは、配列から最後の要素を取り
-
Rubyのfreezeメソッド完全解説 – オブジェクトの可変性と不変性を理解しよう
オブジェクトが「変更可能(ミュータブル)」であるとは、どういう意味なのでしょうか? 難しい言葉に構える必要はありません。「可変性(ミュータビリティ)」とは、単純に「オブジェクトの内部状態を後から変更できる」という意味です。これはすべてのオブジェクトのデフォルトの挙動であり、freeze(凍結)されたオブジェクトや、言語側で特別扱いされている一部のオブジェクトだけが例外となります。 つまり、Rubyのすべてのオブジェクトが変更可能というわけではないのです。 なぜ数値やシンボルは変更できないのか? たとえば、整数・シンボル、さらにはtrueやfalse(これらもすべてオブジェクトです)が変化するの