Защищённые методы
Часть раздела Объектно-ориентированное программирование путешествия по Ruby на Coddy. Урок 18 из 57.
Метод protected занимает промежуточное положение между публичным и приватным. Внешний код не может его вызвать, но любой объект того же класса может вызвать его для другого объекта. Благодаря этому два объекта могут сравнивать данные, которые они не показывают остальной части программы:
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