Menu
Coddy logo textTech

プライベートメソッド

CoddyのRubyジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 17/57。

カプセル化とは、オブジェクトがその仕組みを隠し、少数の公開メソッドを提供することを意味します。メソッドはデフォルトで公開されています。クラス本体で private という語の後に定義されたすべてのメソッドは非公開です。オブジェクト自身のメソッドからは呼び出せますが、外部のコードからは呼び出せません。

class Order
  def initialize(price, quantity)
    @price = price
    @quantity = quantity
  end

  def total
    subtotal + shipping
  end

  private

  def subtotal
    @price * @quantity
  end

  def shipping
    subtotal >= 50 ? 0 : 5
  end
end

order = Order.new(10, 3)
puts order.total
begin
  order.subtotal
rescue NoMethodError => e
  puts e.message
end

出力:

35
private method `subtotal' called for an instance of Order

クラス内では、プライベートメソッドはレシーバーなし、または self. を付けて呼び出します。同じクラスのオブジェクトであっても、別のオブジェクトに対して呼び出すことは拒否されます:

class Coin
  def initialize(cents)
    @cents = cents
  end

  def describe
    "#{self.label} / #{label}"
  end

  def same_as?(other)
    other.label == label
  end

  private

  def label
    "#{@cents}c"
  end
end

a = Coin.new(5)
puts a.describe
begin
  a.same_as?(Coin.new(5))
rescue NoMethodError => e
  puts e.message
end

出力:

5c / 5c
private method `label' called for an instance of Coin

private はメソッド名を受け取ることもでき、def はメソッドの名前を返すため、private def helper とすると、定義したその場所で1つのメソッドだけをprivateにできます。その前後にあるメソッドはpublicのままです。

class Greeter
  def greet(name)
    "#{salutation}, #{name}!"
  end

  private def salutation
    "Hello"
  end

  def wave
    "*waves*"
  end
end

g = Greeter.new
puts g.greet("Ada")
puts g.wave
p Greeter.private_instance_methods(false)

出力:

Hello, Ada!
*waves*
[:salutation]

ヘルパーは非公開にしましょう。公開メソッドは、クラスがプログラムの他の部分に対して約束するものです。非公開メソッドは、呼び出し元を壊すことなく、後から名前を変更したり削除したりできます。

class Invoice
  def total              # public: 呼び出し元がこれに依存している
    net + tax
  end

  private                # 後で自由に変更できる

  def net
    ...
  end

  def tax
    ...
  end
end
challenge icon

チャレンジ

簡単

Orderクラスを完成させてください。initialize以外の唯一のpublicメソッドはreceiptで、3 x 12.50 = 37.50, tax 7.50, total 45.00を返します。privateメソッドのsubtotal(価格と数量の積)、tax(小計の20%)、totalが数値を計算します。

提供されたコードは、quantity price形式の行として注文を読み込み、それぞれのレシートを出力します。その後、外部からtaxの呼び出しを試み、Rubyが拒否するとtax is privateを出力します。

コードはorder.rbに記述します。main.rbには提供された入出力コードが含まれており、編集できません。

自分で試してみよう

require_relative 'order'

# 提供された入出力コード: そのままにしておく
input = []
while (line = gets)
  input << line.chomp
end
orders = input.map do |line|
  quantity, price = line.split
  Order.new(quantity.to_i, price.to_f)
end
orders.each { |o| puts o.receipt }
begin
  orders[0].tax
  puts "tax is public"
rescue NoMethodError
  puts "tax is private"
end
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Rubyオンラインコンパイラ