Standardní objektový systém Perlu 5 dnes je již poměrně zastaralý a proto by mohlo být zajímavé poohlédnout se po alternatovách. Tou nejznámější je Moose. Článek je úvodem do studia tohoto tématu a přináší základní myšlenky práce s Moose.
7.4.2010 00:00 | Jiří Václavík | přečteno 11414×
Perl je jazyk, umožňující objektově-orientovaný způsob programování již od verze 5.000 z roku 1994. I proto má velmi daleko k dnešním objektově-orientovaným jazykům. Cílem Moose (v angličtině označuje moose losa nebo někdy jeden z jeho druhů) je přiblížení Perlu moderním objektovým jazykům. Moose je postaven na základech Class::MOP.
Moose samotný neumí o tolik více než čistý Perl. Za uživatele však odvede spoustu práce a výsledný kód je kratší a přehlednější. V této minisérii se například vůbec nesetkáme s funkcí bless, budeme psát podstatně méně metod než dosud, budeme srozumitelněji deklarovat atributy a neuvidíme žádné odkazy.
Před studiem Moose je vhodné se alespoň zběžně podívat, jak funguje standardní objektový systém v Perlu. Bude pak snažší pochopit práci s Moose.
Moose je řešením objektového systému pro Perl 5. V připravovaném Perlu 6 se počítá s novým modelem, kde budou pro OOP nová klíčová slova.
Jediná věc, která je potřebná před používáním Moose je stažení a nainstalování modulu z CPANu. To tradičně zajistí následující příkaz.
$ cpan Moose
Moose exportuje funkce, které můžeme používat podobně jako klíčová slova jazyka (a tak je také budeme dále nazývat). Za chvíli se s některými z nich seznámíme.
Zopakujme si nejprve, jak jsme vytvářeli objekty v čistém Perlu. Pokaždé jsme definovali nějaký balíček a v něm jsme vytvořili konstruktor - tedy metodu s názvem new. Kód začátku objektového modulu mohl vypadat takto.
package PoStaru;
sub new {
my $trida = shift;
my $objekt = {};
bless $objekt, "PoStaru";
return $objekt;
}
Co když teď použijeme Moose? Zde podobnou věc uděláme snadno.
package PomociMoose;
use Moose;
Je vidět, že kódu je v této fázi u Moose mnohem méně. Konkrétně stačí dva řádky. Moose si již vytvoří metodu new sám (přesněji řečeno ji zdědí z Moose::Object, ze které nyní budou dědit všechny naše třídy). Vzápětí uvidíme, jak se s ní pracuje.
Poznamenejme také, že Moose navíc automaticky zapne režimy warnings a strict.
V čistém Perlu jsou atributy většinou uloženy v hashi. To je jednoduché a poměrně efektivní. Problém později bývá v tom, že je obvykle třeba definovat řadu metod, které parametry například pouze vracejí nebo přenastavují. Samotný hash to neobstará, a tak je na řadě objektový systém.
Tady by se většina uživatelů asi zeptala, zda to nejde jednodušeji a neexistuje něco jako automatické vytvoření takových metod. Standardní objektový systém jejich automatické vytvoření neumožňuje. Avšak s použitím externích modulů to samozřejmě možné je.
Můžeme kupříkladu využít modulu Class::Accessor, který nám snadno vytvoří potřebné metody a atributy.
Podívejme se na jednoduchý příklad. Stačí nastavit Class::Accessor jako rodiče naší třídy a pomocí metody mk_accessors vytvořit atributy a metody, které se použijí k nastavení nebo získání hodnot. Díky tomu můžeme definovat všechny metody a atributy jediným řádkem.
package MojeTrida;
use base qw(Class::Accessor);
MojeTrida->mk_accessors(qw(nazev cena info));
$sluzba = MojeTrida->new();
$sluzba->nazev("strihani vlasu");
$sluzba->cena(100);
$sluzba->info("bla bla bla");
print $sluzba->get("nazev");
print $sluzba->get(qw(nazev cena info));
Co vše Class::Accessor dokáže, se lze dočíst v dokumentaci. Je toho dost. Stejně jako Class::Accessor ale dokáže s atributy pracovat Moose.
Nyní se už budeme věnovat systému Moose. Podívejme se nejprve, jak pracuje s atributy ten.
Atribut se vytváří pomocí klíčového slova has, kterému předáme dvě hodnoty. Těmi jsou požadované jméno atributu a hash s danou strukturou. Touto strukturou se budeme ještě dále zabývat.
Zde je pro začátek jednoduchý příklad, který vytvoří třídu a tři atributy.
package MojeTrida;
use Moose;
has "nazev" => (
is => "rw",
isa => "Str"
);
has "cena" => (
is => "rw",
isa => "Int"
);
has "info" => (
is => "rw",
isa => "Str"
);
Hash parametrů může obsahovat řadu různých položek. My jsme zatím použili pouze dvě. is určuje, zda má být umožněno do atributu zapisovat (tj. read-write; v takovém případě se nastavuje hodnota rw) nebo nikoliv (tj. read-only; píše se jako ro).
Pomocí isa se zapíná typovou kontrolu. Lze použít například hodnoty Str, Num, Bool, HashRef. Pokud hodnotou atributu má být objekt, můžeme zde vepsat i jméno třídy. To bychom využili například pro atribut uchovávající datum a čas posledního přístupu k naší stránce.
has "posledni_pristup" => (
is => "rw",
isa => "DateTime"
);
Pro další možnosti okolo typů jako třeba co všechno za typy lze zadávat, jak definovat nové typy nebo subtypy pomocí regulárních výrazů, je užitečné nahlédnout do dokumentace.
Je dobré si uvědomit, že has je obyčejná funkce. Proto s ni podle toho můžeme zacházet. Předchozí kód bychom mohli přepsat nějak takto.
for (qw(nazev cena info)) {
has $_ => (is => "rw", isa => zjisti_typ($_));
}
Také je možné nastavit více atributů pomocí jednoho volání has. Zde je opět příklad.
has ["nazev", "info"] => (is => "rw", isa => "Str");