Moose: Porovnání verzí

Smazaný obsah Přidaný obsah
Kychot (diskuse | příspěvky)
m →‎Externí odkazy: Moose examples
Kychot (diskuse | příspěvky)
Vrácení omylem vymazaného textu: http://cs.wikiversity.org/w/index.php?title=Moose&curid=7767&diff=30095&oldid=30094
Řádek 69:
* Konkrétní ''instance'' se vytvářejí pomocí konstruktoru ''new''
* ''metoda'' je funkce, asociovaná s třídou. Když se volá, má vždy nějaký ''invokant'', se kterým metoda pracuje:
** když vytváříme nový objekt, je tím invokantem ''jméjméno třídy''
** když voláme metodu u konkrétní instance, je tím invokantem ''tato instance''.
* ''Invokant'' se v Perlu předává funkci jakožto ''první argument''.
 
I když se nejedná o nějaký předpis jazyka Perl, jde o určitou konvenci, že jména tříd začínají velkými písmeny (třída je jakoby větší, protože může mít mnoho instatncí), zatímco jména instancí začínají malými písmeny, tedy je: ''Kocka líza''. (Je to přesně naopak než v češtině, angličtině i jiných jazycích, kde píšeme ''kočka Líza.) Pokud se nám to nelíbí, nemusíme samozřejmě tuto konvenci dodržovat.
 
<source lang='perl' line>
#! /usr/bin/perl
 
use Modern::Perl;
use utf8;
binmode STDOUT, ':utf8';
 
{
package Kocka;
use Moose;
 
sub mňau
{
my $self = shift;
say 'Mňau!';
}
}
 
my $líza = Kocka->new();
my $mňouk = Kocka->new();
 
$líza->mňau();
$mňouk->mňau();
</source>
 
*1. Říkáme shellu, který program má interpretovat tento skript.
*2. Programujeme ve stylu Modern::Perl.
*4. Co je ve skriptu, bude bráno jako znaky [[UTF-8]]
*5. Co půjde na standardní výstup, bude chápáno také jako text v UTF-8
*7. Začneme nový blok (složená závorka), protože to bude nový balík s vlastním jmenným prostorem.
*8. Vytvářím ''třídu'' Kocka.
*9. Používám k tomu knihovnu Moose. (Tím je dané např. i implicitní vytvoření konstruktoru ''new''.)
*11. Podprogram, přesněji řečeno ''metoda'' mňau, kde říkám, jak má libovolná kočka mňoukat.
*13. Uložíme invokant (tedy první parametr funkce) do proměnné $self.
*14. Tady konečně říkám, jak má kočka mňoukat.
*18.–19. Postupně vytvářím dvě instance koček, tedy dva konkrétní případy, kočky Lízu a Mňouka.
*21.-22. Vyzkouším si, jak mňoukají.
 
Výstup skriptu bude jednoduchý:
<pre>
Mňau!
Mňau!
</pre>
 
Někdo namítne, že je to nedokonalé, že Mňouk je kocour a ten že mňouká jinak. Námitka je na místě, časem zjistíme, že je možno vytvářet i různá pohlaví, která budou mňoukat jinak.
 
=== 02. Atributy ===
 
Když už vytváříme takovéto kočky, bylo by dobré, aby samy kočky věděly, jak se jmenují a mohly se nám na požádání třeba představit. Tedy všechny kočky (tj. třída koček) by měla mít nějaký šuplíček, kam by se ukládalo jméno té které kočky. A pak třeba její věk (kolik je jí let) a jestli třeba nemá nějakou dietu (třeba vytváříme databázi pacientů v kočičí nemocnici).
 
Tyto tzv. ''atributy'' (někdy se jim říká ''stav'' anebo prostě data dané instance) se v ''Mose'' přikládají pomocí funkce <tt>has()</tt>; zde je možné rovněž určit, jestli je možné tento atribut dále měnit a jaký typ proměnné bude použit, což představuje určitý typ kontroly nad tím, jak budeme moci s objektem nakládat.
 
<source lang='perl' line>
#! /usr/bin/perl
 
use Modern::Perl;
use utf8;
binmode STDOUT, ':utf8';
 
{
package Kocka;
use Moose;
 
has 'jméno', is=>'ro', isa=>'Str';
has 'věk', is=>'rw', isa=>'Int';
has 'dieta', is=>'rw';
}
 
my $tlusťoch = Kocka->new(jméno=>'Tlusťoch', věk=8, dieta=>'produkty moře');
 
say $tlusťoch->jméno(), ', ', $tlusťoch->věk(), ' let, dieta: ', $tlusťoch->dieta();
 
$tlusťoch->dieta( 'neslaná');
say $tlusťoch->jméno(), ', ', $tlusťoch->věk(), ' let, nová dieta: ', $tlusťoch->dieta();
</source>
 
* 11. atribut ''jméno'' je read-only a je to string
* 12. atribut ''věk'' je read/write a je to číslo
* 13. atribut ''dieta'' je read/write a není řečeno, jaký typ proměnné to bude
* 16. vytvoříme tlusťocha, který se jmenuje ''Tlusťoch'', je mu 8 let a má speciální dietu
* 18. vypíšeme výše zadané informace o tlusťochovi a to pomocí samočinně vytvořených metod (kterým se říká ''akcesory''), které se volají ''bez argumentů'' (prázdné závorky)
* 20. změníme mu dietu pomocí metody ''dieta'', která se automaticky vytvořila právě z účelem změny atributu; formálně je shodná s akcesorem, akorát že se volá s příslušným argumentem; takové metodě se pak říká ''mutátor''
* 21. znovu vypíšeme status
 
Výstup programu:
<pre>
Tlusťoch, 8 let, dieta: produkty moře
Tlusťoch, 8 let, nová dieta: neslaná
</pre>
 
=== 03. Enkapsulace ===
 
Enkapsulace neboli ''zapouzdření'' znamená, že se skryjí vnitřní detaily objektu.
 
Příklad: Namísto toho, abychom zadávali věk kočky, zadáme datum jejího narození a její věk se pak automaticky spočítá. Pozměníme třídu Kocka:
 
<source lang='perl'>
{
package Kocka;
use Moose;
 
has 'jméno', is=>'ro', isa=>'Str';
has 'dieta', is=>'rw';
has 'rok_narození', is=>'ro', isa=>'Int';
 
sub věk {
my $self = shift;
my $rok = (localtime)[5] + 1900;
return $rok - $self->rok_narození;
}
}
</source>
 
Pomineme, že věk zde počítáme jen přibližně (zanedbáváme datum narození), ale co je důležité:
# změnil se popis třídy: namísto atributu ''věk'' je zde uložen atribut ''rok narození'' a je definována metoda na výpočet věku
# způsob volání se přitom ale nezměnil – věk dané kočky zjistíme stejně jako předtím:
<source lang='perl'>
say $tlusťoch->věk();
</source>
Tak to je ta enkapsulace: Zatímco se nějaký vnitřní mechanismus třídy změnil, zvenku se to chová stále stejně; při volání metody nás jakoby nemusí zajímat, jak je to uvnitř té třídy zařízeno, že to tak funguje, hlavně, že to funguje.
 
Další výhoda takového přístupu je, že si můžeme definovat nějaké defaultní hodnoty, které konstruktor objektu použije v případě, že nějaké atributy nejsou zadány explicitně; například předpokládáme, že zakládáme rodný list kočky a tím pádem můžeme předpokládat, že pokud nezadáme její rok narození, bude se jednat o nynější rok; pak defaultní hodnotu tohoto atributu definujeme např. následovně:
<source lang='perl'>
has 'rok_narození', is=>'ro', isa=>'Int',
default => sub{(localtime)[5] + 1900};
</source>
 
<source lang='perl'>
</source>
 
[[Kategorie:Perl]]