Menu
Coddy logo textTech

Приватные методы

Часть раздела Объектно-ориентированное программирование путешествия по Ruby на Coddy. Урок 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 делает один метод приватным прямо в месте его определения. Методы выше и рядом с ним остаются публичными:

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, — это receipt, который возвращает 3 x 12.50 = 37.50, tax 7.50, total 45.00. Закрытые методы subtotal (цена, умноженная на количество), tax (20% от промежуточного итога) и total вычисляют эти числа.

Предоставленный код считывает заказы в виде строк quantity price и выводит каждый чек. Затем он пытается вызвать tax извне и выводит tax is private, когда Ruby отклоняет вызов.

Ваш код должен находиться в 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