Защищённые методы
Часть раздела Объектно-ориентированное программирование путешествия по Ruby на Coddy. Урок 18 из 57.
Метод protected занимает промежуточное положение между public и private. Код за пределами класса не может его вызвать, но любой объект того же класса может вызвать его у другого объекта. Это позволяет двум объектам сравнивать данные, которые они не показывают остальной части программы:
class Account
def initialize(owner, balance)
@owner = owner
@balance = balance
end
def richer_than?(other)
balance > other.balance
end
protected
def balance
@balance
end
end
ada = Account.new("Ada", 500)
bo = Account.new("Bo", 300)
puts ada.richer_than?(bo)
begin
ada.balance
rescue NoMethodError => e
puts e.message
endВывод:
true
protected method `balance' called for an instance of AccountРазница с private проявляется, когда получателем является другой объект. other.balance работает для защищённого метода и не работает для приватного:
class Sample
def initialize(n)
@n = n
end
def compare_protected(other)
other.guarded + guarded
end
def compare_private(other)
other.hidden + hidden
rescue NoMethodError
"private refused other.hidden"
end
protected
def guarded
@n
end
private
def hidden
@n
end
end
a = Sample.new(1)
b = Sample.new(2)
puts a.compare_protected(b)
puts a.compare_private(b)Вывод:
3
private refused other.hiddenprotected также работает с attr_reader — это обычный способ сделать значение доступным только объектам одного класса, например, чтобы определить, какой из двух объектов побеждает:
class Player
attr_reader :name
def initialize(name, rating)
@name = name
@rating = rating
end
def stronger?(other)
rating > other.rating
end
protected
attr_reader :rating
end
a = Player.new("Ada", 1200)
b = Player.new("Bo", 1100)
puts a.stronger?(b)
puts [a, b].select { |pl| pl.stronger?(b) }.map(&:name).inspectВывод:
true
["Ada"]Выбирайте самый узкий подходящий уровень. public — для интерфейса класса, protected — для данных, с которыми объекты класса сравниваются друг с другом, а private — для всего остального:
public # кто угодно: order.total
protected # объекты класса: other.balance внутри Account
private # только сам объект: subtotal, self.subtotalЗадание
ЛегкоЗавершите класс Account. Баланс должен быть доступен для чтения только другим аккаунтам: сделайте его средство чтения защищённым. richer_than?(other) сравнивает балансы, transfer_to(other, amount) переводит деньги на другой аккаунт через защищённый метод другого аккаунта receive(amount) и возвращает true либо возвращает false, если баланс слишком мал. to_s возвращает только имя владельца.
Предоставленный код считывает имена двух владельцев и их балансы, затем команды transfer a b 50, выводя ok или refused. Затем он выводит Ada is richer (или Bo is richer, или equal) и наконец пытается прочитать balance извне, выводя balance is protected, когда Ruby отказывает в доступе.
Ваш код должен находиться в account.rb. В main.rb содержится предоставленный код ввода/вывода, и его нельзя изменять.
Попробуйте сами
require_relative 'account'
# Предоставленный код ввода/вывода: оставьте его как есть
input = []
while (line = gets)
input << line.chomp
end
accounts = input[0..1].map do |line|
owner, balance = line.split
Account.new(owner, balance.to_i)
end
a, b = accounts
input.drop(2).each do |line|
_, from, to, amount = line.split
source = from == "a" ? a : b
target = to == "a" ? a : b
puts source.transfer_to(target, amount.to_i) ? "ok" : "refused"
end
if a.richer_than?(b) then puts "#{a} is richer"
elsif b.richer_than?(a) then puts "#{b} is richer"
else puts "equal"
end
begin
a.balance
puts "balance is public"
rescue NoMethodError
puts "balance is protected"
end
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Классы и объекты
Работа с файламиОпределение классовПеременные экземпляраМетоды и selfto_s и inspectПовторение — читательский билет4Инкапсуляция
Приватные методыЗащищённые методыПриватные сеттерыЗащита состоянияПовторение — торговый автомат7Полиморфизм и утиная типизация
ПолиморфизмУтиная типизацияАбстрактные методыcase и классыПовторение — способы оплаты10Шаблоны проектирования, часть 2
Делегирование с помощью ForwardableШаблон декоратораШаблон строителяШаблон состояния2Аксессоры и self
Чтение и записьПользовательские сеттерыself в методахИдентичность и равенствоПовторение — список контактов5Наследование
ПодклассыПереопределение методовВызов superis_a? и предкиПовторение — расчёт зарплаты сотрудников8Специальные методы
Равенство и хешированиеМетоды операторовИндексация и добавлениеПользовательские коллекцииПовторение — дроби11Проект: Управление библиотекой
Книги и читателиВыдача книг3Методы и переменные классов
Методы классовПеременные экземпляра классаКонстантыФабричные методыПовторение — коды купонов6Модули и примеси
Модули и includeРасширение объектовМодуль ComparableМодуль EnumerableПовторение — спортивная лига9Паттерны проектирования. Часть 1
Паттерн «Одиночка»Фабричный паттернПаттерн «Наблюдатель»Паттерн «Стратегия»Потренируйтесь самостоятельно: Онлайн-компилятор Ruby