Ruby po kapkách (13.) – přístup k metodám, moduly
Jak jsme se dozvěděli již v úvodu série o OOP v Ruby, platí, že proměnné definované v rámci třídy jsou pro okolní program skryté a je možné k nim přistupovat jen pomocí příslušných metod. Možná vás napadlo, zda je možné omezit také přístup k některým metodám. Ve skutečnosti jsme se s jednou metodou, k níž nelze přistupovat mimo definici třídy již setkali.
a = Basic.new(1, 2, 3)
a.initialize(4, 5, 6)
Spuštění tohoto fragmentu kódu skončí chybou.
private method ‚initialize‘ called for #<Basic:0xa03bcc0>(NameError)
Metoda initialize
je totiž v Ruby označena jako private a pokus o její volání končí vznikem výjimky. Celkem mohou být metody v Ruby z hlediska řízení přístupu zařazeny do tří skupin:
- public
- protected
- private
(Hned na tomto místě upozorněme, že význam označení protected je v Ruby mírně odlišný od jazyků C++ nebo Java.)
Není-li stanoveno jinak, jsou nově definované metody automaticky označeny jako public. To umožňuje jejich volání jinými metodami téže třídy i jakýmikoliv kódem mimo třídu. Metoda initialize
je automaticky označena jako private. Tyto metody lze volat pouze v rámci definice třídy, ve které jsou definovány. Jinými slovy můžeme říci, že je lze volat pouze bez určení objektu – příjemce (tj. není možné použít volání ve formě objekt.metoda a tudíž je volání možné vlastně jen v rámci jedné instance).
Metody označené jako protected tvoří střední cestu. Lze je volat v rámci definice stejné třídy. Navíc mohou být volány s určením objektu, ten musí však opět patřit do stejné třídy. Tyto metody tesy mohou být volány navzájem mezi instancemi jedné třídy.
K přepínání přístupu k metodám existují v Ruby dva jednoduché způsoby:
class Dummy
# defaultně jsou metody public
#
private
# metody definované tady jsou private
#
protected
# metody definované tady jsou protected
#
public
# metody definované tady jsou opět public
#
# alternativně můžeme přístup k metodám nastavit hromadně
public :method1, :method4
protected :method2
private :method3
end
Vraťme se na chvíli k našemu příkladu s robotickou hrou. Čas běží a investoři tlačí na urychlení vývoje. Rozhodli jsme se proto zdokonalit definici třídy Movable
. Nebudeme nyní nastavovat hodnoty směru a rychlosti přímo, ale vytvoříme metody pro zatáčení a akceleraci. Přímé nastavení hodnot by již nemělo být možné. Dále připravíme triviální metodu, která bude simulovat srážku objektu s jiným objektem. Prozatím se spokojíme s tím, že kolize náhodně změní směr a rychlost obou dotčených objektů. Budeme rozšiřovat poslední verzi definice třídy Movable
.
class Movable # při doplnění definice nemusíme opakovat určení předka
protected :direction=, :velocity= # nastavování hodnot bude protected
def steer(s) # metoda pro změnu směru objektu
@direction += s # směr se změní o zadaný parametr
end
def accelerate(a) # metoda pro změnu rychlosti objektu
@velocity += a # rychlost se změní o zadaný parametr
end
def crash(o) # simulace srážky s jiným objektem
direction = rand(direction) # vlastní rychlost a směr se náhodně
velocity = rand(velocity) # změní
o.direction = rand(o.direction) # a změní se i rychlost a směr objektu
o.velocity = rand(o.velocity) # zadaného jako parametr
end
end
Doplněnou definici ihned vyzkoušíme.
a = Movable.new(3, 3, 10, 10, 5)
puts a.to_s
b=Movable.new(3, 3, 10, 7, 13)
puts b.to_s
a.crash(b) # objekt ‚a‘ dostal zprávu, aby narazil do objektu ‚b‘
puts a.to_s
puts b.to_s
a.steer(3) # objekt ‚a‘ zatáčí
puts a.to_s
b.direction = 7 # objekt ‚b‘ se pokouší o přímé nastavení směru
Získáme výpis podobný tomuto:
Movable: X = 3, Y = 3, M = 10kg, C = 1, D = 10, V = 5
Movable: X = 3, Y= 3, M = 10kg, C = 2, D = 7, V = 13
Movable: X = 3, Y= 3, M = 10kg, C = 2, D = 10, V = 5
Movable: X = 3, Y= 3, M = 10kg, C = 2, D = 6, V = 1
Movable: X = 3, Y= 3, M = 10kg, C = 2, D = 13, V = 5
protected method ‚direction=‘ called for #<Movable:0xa03bca8>(NameError)
Zatímco objekty mohou navzájem volat své metody označené jako protected, volání z kódu mimo objekt skončilo výjimkou.
Řízení přístupu k metodám představuje po izolaci proměnných další podobu objektového principu zapouzdření. Na poněkud obecnější úrovni lze říct, že velká část úspěchu OOP tkví v poskytnutí prostředků pro organizaci zdrojového kódu do ucelených bloků. Hotové části kódu s dobře dokumentovaným rozhraním lze použít i v budoucích aplikacích a značně se tak zrychluje vývoj.
Třída je v OOP základní konstrukcí pro logické strukturování programů. Na druhé straně stojí fyzické rozdělení kódu do více souborů. K němu v Ruby slouží obvyklý mechanismus vložení souboru realizovaný voláním require
.
require ‚date‘ # vložíme soubor ‚date.rb‘, kde je definována třída ‚Date‘
puts Date.today # vyzkoušíme třídu ‚Date‘
Výsledkem je dnešní datum. Součástí instalace Ruby je knihovna standardních tříd, které jsou uloženy ve větším počtu menších souborů. Definici potřebných tříd můžeme do programu vkládat voláním require
. Metoda require
nahradí svůj výskyt v kódu obsahem souboru, který jí předáme jako parametr.
Pro hledání souboru existují relativně složitá pravidla. Defaultně se hledá v adresářích, kde jsou uloženy součásti standardní knihovny a v aktuálním adresáři. Pokud není soubor nalezen, pokouší se interpret ještě přidat k názvu koncovku .rb
nebo koncovky dynamických knihoven na dané platformě (například .so
nebo .dll
). Tímto způsobem se načítají knihovny napsané v jiných jazycích a zkompilované do nativního kódu.
Při běhu programu máme k dispozici dvě globální proměnné, které nám poskytují informace o prohledávaných adresářích a o aktuálně načtených souborech pomocí require
.
require ‚date‘ # vložíme soubor
puts $: # proměnná, která obsahuje cesty prohledávané metodou require
puts
puts $“ # proměnná, která obsahuje názvy načtených souborů
Zobrazí se několik řádků, které mohou vypadat například takto.
/usr/local/lib/ruby/site_ruby/1.8
/usr/local/lib/ruby/site_ruby/1.8/i386-freebsd7
/usr/local/lib/ruby/site_ruby
/usr/local/lib/ruby/1.8
/usr/local/lib/ruby/1.8/i386-freebsd7
.
date.rb
Volání metody require
se může v kódu programu objevit prakticky kdekoliv, kde je možné volat metodu. Možné je i vícenásobné vložení stejného souboru (například do několika různých definic tříd).
Někde mezi třídou a souborem se nachází ještě jedna úroveň organizování kódu, kterou lze v Ruby použít. Jsou jí moduly. Modul je ohraničená část kódu velmi podobná definici třídy. Nejlépe si problematiku objasníme na příkladu. Vraťme se proto opět k vyvíjené hře. Za účelem urychlení prací byl najat další tým, který se zabývá programovaním matematických a fyzikálních funkcí, které budeme v simulaci potřebovat. Prvním výsledkem je modul Matphys
, který nabízí metodu pro výpočet vzdálenosti dvou bodů na ploše.
module Matphys # začátek definice modulu
def Matphys.distance(x1, y1, x2, y2)
Math.sqrt((x2 – x1) * (x2 – x1) + (y2 – y1) * (y2 – y1)) # 2D vzdálenost
end
end # konec definice modulu
puts Matphys.distance(3, 4, 5, 6) # ověříme funkci metody z modulu
Výsledkem testovacího výpisu, který následuje definici modulu je:
2.828427125
Metoda Matphys.distance
je definována včetně názvu modulu a musíme ji také tak volat. Jedná se o analogii s metodami tříd. Při pozornějším pohledu na metodu Matphys.distance
uvidíte volání Math.sqrt
, což je metoda pro výpočet odmocniny. Pokud hádáte, že Math
je modul, hádáte správně. Kromě tříd je část standardní knihovny v Ruby organizována do modulů.
Stejně jako definice třídy, ani definice modulu není uzavřena a můžeme ji kdykoliv doplnit:
module Matphys
G = 9.81 # definice konstanty
end
puts Matphys::G # testovací výpis konstanty z modulu
Nadefinovali jsme v modulu konstantu. Výsledkem výpisu je samozřejmě:
9.81
V modulech je možné používat i proměnné. To má však smysl spíše v případě, kdy Ruby využívá moduly jako takzvané mixiny. O tom však zase až v příštím díle.
Starší komentáře ke článku
Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.
Mohlo by vás také zajímat
-
Co je to VRAM a jak ji navýšit bez drahého upgradu?
20. srpna 2024 -
inPage AI: Revoluční nástroj pro tvorbu webů
3. července 2024 -
Jak nainstalovat šablonu ve WordPressu
23. července 2024
Nejnovější
-
Jak rozšířit úložiště Macu za pětinovou cenu?
16. prosince 2024 -
Nové trendy v doménách pro osobní projekty – DIY, LIVING a LIFESTYLE
9. prosince 2024 -
Jak chránit webové stránky před Web/AI Scrapingem
27. listopadu 2024 -
Jaký monitor je nejlepší k novému Macu Mini?
25. listopadu 2024