基礎

Rubyのアクセス修飾子入門|public・private・protectedの使い方

アクセス修飾子はメソッドの公開範囲を制御する仕組みです。Rubyにはpublicprivateprotectedの3つのアクセス修飾子があり、これらを使ってクラスの外部からアクセスできるメソッドとできないメソッドを区別します。カプセル化(内部実装の隠蔽)はオブジェクト指向の重要な原則です。

基本的な使い方

public(デフォルト)

特に指定しない場合、メソッドはpublicになります。クラスの外部から自由に呼び出せます。

Ruby
class User
  def greet  # publicメソッド(デフォルト)
    puts "こんにちは、#{full_name}です"
  end

  private

  def full_name  # privateメソッド
    '田中太郎'
  end
end

user = User.new
user.greet       # OK: publicメソッド
# user.full_name  # エラー!privateメソッドは外部から呼べない
実行結果
こんにちは、田中太郎です

privateと書いた行以降に定義されたメソッドはすべてprivateになります。privateメソッドはクラス内の他のメソッドからのみ呼び出すことができ、外部からのアクセスはエラーになります。

3つのアクセス修飾子の違い

Ruby
class Account
  attr_reader :name, :balance

  def initialize(name, balance)
    @name = name
    @balance = balance
  end

  # public: 外部から呼べる
  def deposit(amount)
    if valid_amount?(amount)
      @balance += amount
      log_transaction('入金', amount)
      puts "#{amount}円を入金しました(残高: #{@balance}円)"
    end
  end

  # public: 他のAccountと比較
  def richer_than?(other)
    balance > other.balance_value  # protectedメソッドにアクセス
  end

  protected

  # protected: 同じクラスのインスタンス間でアクセス可能
  def balance_value
    @balance
  end

  private

  # private: このクラス内からのみ呼べる
  def valid_amount?(amount)
    if amount <= 0
      puts 'エラー: 金額は正の数を指定してください'
      false
    else
      true
    end
  end

  def log_transaction(type, amount)
    puts "[LOG] #{type}: #{amount}円"
  end
end

acc1 = Account.new('太郎', 10000)
acc2 = Account.new('花子', 20000)

acc1.deposit(5000)
puts "太郎は花子より裕福?: #{acc1.richer_than?(acc2)}"
# acc1.balance_value  # エラー!protectedは外部から呼べない
# acc1.valid_amount?(100)  # エラー!privateは外部から呼べない
実行結果
[LOG] 入金: 5000円
5000円を入金しました(残高: 15000円)
太郎は花子より裕福?: false

privateメソッドの詳細

Ruby
class Calculator
  def calculate(a, b, operation)
    case operation
    when :add then format_result(a, b, '+', add(a, b))
    when :subtract then format_result(a, b, '-', subtract(a, b))
    when :multiply then format_result(a, b, '*', multiply(a, b))
    else puts '未対応の演算です'
    end
  end

  private

  def add(a, b)
    a + b
  end

  def subtract(a, b)
    a - b
  end

  def multiply(a, b)
    a * b
  end

  def format_result(a, b, op, result)
    puts "#{a} #{op} #{b} = #{result}"
  end
end

calc = Calculator.new
calc.calculate(10, 3, :add)
calc.calculate(10, 3, :subtract)
calc.calculate(10, 3, :multiply)
実行結果
10 + 3 = 13
10 - 3 = 7
10 * 3 = 30

外部からはcalculateメソッドだけを呼び出せます。個々の計算処理(addsubtractなど)はprivateにすることで、内部実装を隠蔽しています。

個別にアクセス修飾子を指定

Ruby
class MyClass
  def method_a
    puts 'public method_a'
  end

  # 個別にprivateを指定する方法
  private def method_b
    puts 'private method_b'
  end

  def method_c
    puts 'public method_c'
    method_b  # private methodを内部から呼ぶ
  end
end

obj = MyClass.new
obj.method_a
obj.method_c
# obj.method_b  # エラー!
実行結果
public method_a
public method_c
private method_b
protectedの使いどころ

protectedは同じクラス(またはサブクラス)のインスタンス間でのみアクセスを許可します。主にオブジェクト同士の比較(==メソッドなど)で、内部の値にアクセスする必要がある場合に使います。

Rubyのprivateは絶対ではない

Rubyではsendメソッドを使うとprivateメソッドでも外部から呼び出せてしまいます(obj.send(:method_b))。privateはあくまで「誤って呼ばないようにする」ための仕組みであり、セキュリティ機能ではありません。

まとめ

  • public: 外部から自由に呼び出せる(デフォルト)
  • private: クラス内部からのみ呼び出せる
  • protected: 同じクラスとサブクラスのインスタンス間でアクセス可能
  • private以降のメソッドはすべてprivateになる
  • 内部実装を隠蔽することで、クラスの使いやすさと保守性が向上する