Akcesory

edytuj

Czym jest akcesor?

edytuj

Krótko omówiliśmy zmienne instancji we wcześniejszym rozdziale, ale jeszcze za wiele z nimi nie robiliśmy. Zmienne instancji obiektu są jego atrybutami, to te rzeczy, które odróżniają obiekt od innych obiektów tej samej klasy. Za ważną czynność zapisywania i odczytywania atrybutów odpowiedzialne są metody nazywane akcesorami atrybutów. Jak za chwilę zobaczymy, nie musimy pisać akcesorów bezpośrednio. Wcześniej jednak poznajmy wszystkie etapy ich tworzenia.

Wyróżniamy dwa rodzaje akcesorów: piszące (ang. writer[1]) i czytające (ang. reader[2]).

class Owoc
  def zapisz_rodzaj(r)    # akcesor piszacy
    @rodzaj = r
  end
  
  def czytaj_rodzaj       # akcesor czytajacy
    @rodzaj
  end
end

o1 = Owoc.new

# uzycie akcesora piszacego:
o1.zapisz_rodzaj("brzoskwinia")

# uzycie akcesora czytajacego:
o1.czytaj_rodzaj #=> "brzoskwinia"

Gdybyśmy wpisali powyższy kod do irba, moglibyśmy zastosować następujący sposób inspekcji:

irb(main):011:0> o1
=> #<Owoc:0x2e47044 @rodzaj="brzoskwinia">

Proste prawda? Możemy przechowywać i odczytywać informację o tym, na jaki owoc patrzymy. Ale nasze nazwy metod są nieco rozwlekłe. W następującym przykładzie są już nieco bardziej zwięzłe i konwencjonalne:

class Owoc
  def rodzaj=(r)
    @rodzaj = r
  end

  def rodzaj
    @rodzaj
  end
end
   
o2 = Owoc.new
o2.rodzaj = "banan"
o2.rodzaj #=> "banan"

Metoda inspect

edytuj

Jest tu potrzebna krótka dygresja. Z pewnością zauważyłeś, że jeżeli próbujemy spojrzeć na obiekt w irbie bezpośrednio, pokazuje się nam coś zagadkowego w rodzaju #<jakisObiekt:0x83678>. To jest po prostu domyślne zachowanie i oczywiście możemy je zmienić. Wszystko, co musimy zrobić to dodać metodę o nazwie inspect. Powinna ona zwracać łańcuch, który opisuje obiekt w jakiś sensowny sposób, włączając stany części lub wszystkich jego zmiennych instancji.

class Owoc
  def inspect
    "owoc rodzaju: #{@rodzaj}"
  end
end

Podobną metodą jest metoda to_s (ang. convert to string - zamień na łańcuch), która jest używana gdy drukujemy obiekt. Ogólnie rzecz biorąc, możesz traktować inspect jako narzędzie, gdy piszesz i debugujesz programy, natomiast to_s jako sposób na formowanie wyjścia programu. irb używa inspect ilekroć wyświetla wyniki. Możesz użyć metody p by łatwo debugować wyjście z programów.

# Te dwie linie są równoważne:
p obiekt
puts obiekt.inspect

Łatwy sposób tworzenia akcesorów

edytuj

Ponieważ wiele zmiennych instancji potrzebuje akcesorów, Ruby dostarcza wygodne skróty dla standardowych form.

Skrót Efekt
attr_reader :v def v; @v; end
attr_writer :v def v=(value); @v=value; end
attr_accessor :v attr_reader :v; attr_writer :v
attr_accessor :v, :w attr_accessor :v; attr_accessor :w

Korzystając z tabeli uporządkujmy naszą klasę i dodajmy informację na temat świeżości. Najpierw automatycznie wygenerujemy akcesory: czytające i piszące, a następnie dodamy nową informację do metody inspect:

class Owoc
  attr_accessor :stan
  attr_accessor :gatunek
  
  def inspect
    "#{@stan} owoc rodzaju: #{@gatunek}"
  end
end

o = Owoc.new
o.gatunek = "banan"
o.stan = "dojrzaly"
p o #=> dojrzaly owoc rodzaju: banan

Więcej zabawy z owocem

edytuj

Jeżeli nikt nie zjadł naszego dojrzałego owocu, może należałoby pozwolić, by czas zebrał swoje żniwo (poniższy kod możemy dopisać bezpośrednio do powyższego):

class Owoc
  def uplywa_czas
    @stan = "gnijacy"
  end
end

p o #=> dojrzaly owoc rodzaju: banan
o.uplywa_czas
p o #=> gnijacy owoc rodzaju: banan

W następnym rozdziale zobaczymy, jak zapewnić, by już w momencie utworzenia Owoc miał zdefiniowany rodzaj i stan.

Przypisy

  1. W innych językach programowania powszechnie funkcjonuje nazwa setter.
  2. W innych językach programowania - getter.