Menu
CoddyTech

Metody chronione

Część sekcji Programowanie obiektowe ścieżki Ruby w Coddy. Lekcja 18 z 57.

Metoda protected znajduje się między metodami publicznymi a prywatnymi. Kod spoza klasy nie może jej wywołać, ale każdy obiekt tej samej klasy może wywołać ją dla innego obiektu. Dzięki temu dwa obiekty mogą porównywać dane, których nie pokazują reszcie programu:

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

Wynik:

true
protected method `balance' called for an instance of Account

Różnica w porównaniu z private ujawnia się, gdy odbiorcą jest inny obiekt. other.balance działa w przypadku metody chronionej, a w przypadku prywatnej kończy się niepowodzeniem:

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)

Wynik:

3
private refused other.hidden

protected działa również z attr_reader — to typowy sposób udostępniania wartości tylko obiektom jednej klasy, na przykład w celu ustalenia, który z dwóch obiektów wygrywa:

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

Wynik:

true
["Ada"]

Wybierz najwęższy poziom, który się sprawdzi. public służy do interfejsu klasy, protected do danych, które obiekty tej klasy porównują między sobą, a private do wszystkiego innego:

public      # każdy: order.total
protected   # obiekty tej klasy: other.balance wewnątrz Account
private     # tylko sam obiekt: subtotal, self.subtotal
challenge icon

Wyzwanie

Łatwy

Uzupełnij klasę Account. Saldo może być odczytywane tylko przez inne konta: ustaw dostęp do odczytu jako chroniony. richer_than?(other) porównuje salda, transfer_to(other, amount) przekazuje pieniądze na inne konto za pomocą chronionej metody tego konta receive(amount) i zwraca true albo zwraca false, gdy saldo jest zbyt niskie. to_s zwraca tylko imię właściciela.

Dostarczony kod odczytuje imiona właścicieli i salda, a następnie polecenia transfer a b 50, wypisując ok lub refused. Potem wypisuje Ada is richer (lub Bo is richer, lub equal), a na końcu próbuje odczytać balance z zewnątrz, wypisując balance is protected, gdy Ruby odmówi.

Twój kod umieść w account.rb. main.rb zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.

Spróbuj swoich sił

require_relative 'account'

# Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
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
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Ruby online