Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 3 - Hrací kostka ve VB.NET - Zapouzdření, konstruktor a Random

V předešlém cvičení, Řešené úlohy k 1.-2. lekci OOP ve VB.NET, jsme si procvičili nabyté zkušenosti z předchozích lekcí.

Dnes ve VB.NET tutoriálu začneme pracovat na slíbené aréně, ve které budou proti sobě bojovat dva bojovníci. Boj bude tahový (napřeskáčku) a bojovník vždy druhému ubere život na základě síly jeho útoku a obrany druhého bojovníka. Simulujeme v podstatě stolní hru, budeme tedy simulovat i hrací kostku, která dodá hře prvek náhodnosti. Začněme zvolna a vytvořme si dnes právě tuto hrací kostku. Zároveň se naučíme jak definovat vlastní konstruktor.

Vytvoření projektu

Vytvořme si novou konzolovou aplikaci a pojmenujme ji Arena. K projektu si přidejme novou class s názvem Kostka. Zamysleme se nad atributy, které kostce dáme. Jistě by se hodilo, kdybychom si mohli zvolit počet stěn kostky (klasicky 6 nebo 10 stěn, jak je zvykem u tohoto typu her). Dále bude kostka potřebovat tzv. generátor náhodných čísel. Ten nám samozřejmě poskytne .NET framework, který k těmto účelům obsahuje třídu Random. Naše třída bude mít nyní 2 atributy: pocetSten typu Integer a random typu Random, kde bude generátor náhodných čísel.

Zapouzdření

Minule jsme kvůli jednoduchosti nastavovali všechny atributy naší třídy jako Public, tedy jako veřejně přístupné. Většinou se však spíše nechce, aby se daly zvenčí modifikovat a používá se modifikátor Private. Atribut je poté viditelný jen uvnitř třídy a zvenčí se VB.NET tváří, že vůbec neexistuje. Při návrhu třídy tedy nastavíme vše na Private a v případě, že něco bude opravdu potřeba vystavit, použijeme Public. Naše třída nyní vypadá asi takto:

''' <summary>
''' Třída reprezentuje hrací kostku
''' </summary>
Public Class Kostka
    ''' <summary>
    ''' Generátor náhodných čísel
    ''' </summary>
    Private random As Random
    ''' <summary>
    ''' Počet stěn kostky
    ''' </summary>
    Private pocetSten As Integer
End Class

Konstruktory

Až doposud jsme neuměli zvenčí nastavit jiné atributy než Public, protože např. Private nejsou zvenčí viditelné. Již jsme si říkali něco málo o konstruktoru objektu. Je to metoda, která se zavolá ve chvíli vytvoření instance objektu. Slouží samozřejmě k nastavení vnitřního stavu objektu a k provedení případné inicializace. Kostku bychom nyní v Module1.vb vytvořili takto:

Dim kostka As Kostka = New Kostka()

Právě Kostka() je konstruktor. Protože v naší třídě žádný není, VB.NET si dogeneruje prázdnou metodu. My si však nyní konstruktor do třídy přidáme. Deklaruje se jako metoda, ale nemá návratový typ a musí mít jméno New. V konstruktoru nastavíme počet stěn na pevnou hodnotu a vytvoříme instanci třídy Random. Konstruktor bude vypadat následovně:

Public Sub New()
    pocetSten = 6
    random = New Random()
End Sub

Pokud kostku nyní vytvoříme, bude mít v atributu pocetSten 6 a v random bude vytvořená instance generátoru náhodných čísel. Vypišme si počet stěn do konzole, ať vidíme, že tam hodnota opravdu je. Není dobré atribut nastavit na Public, protože nebudeme chtít, aby nám někdo mohl již u vytvořené kostky měnit počet stěn. Přidáme do třídy tedy metodu VratPocetSten(), která nám vrátí hodnotu atributu pocetSten. Docílili jsme tím v podstatě toho, že je atribut read-only (atribut není viditelný a lze ho pouze číst metodou, změnit ho nelze). VB.NET má k tomuto účelu ještě další konstrukce, ale tím se zatím nebudeme zabývat. Nová metoda bude vypadat asi takto:

''' <summary>
''' Vrátí počet stěn kostky
''' </summary>
''' <returns>Počet stěn kostky</returns>
Public Function VratPocetSten() As Integer
    Return pocetSten
End Function

Přesuňme se do Module1.vb a vyzkoušejme si vytvořit kostku a vypsat počet stěn:

Dim kostka As Kostka = New Kostka()
Console.WriteLine(kostka.VratPocetSten())
Console.ReadKey()

Výstup:

Konzolová aplikace
6

Vidíme, že se konstruktor opravdu zavolal. My bychom ale chtěli, abychom mohli u každé kostky při vytvoření specifikovat, kolik stěn budeme potřebovat. Dáme tedy kostruktoru parametr:

Public Sub New(aPocetSten As Integer)
    pocetSten = aPocetSten
    random = New Random()
End Sub

Všimněte si, že jsme před název parametru metody přidali znak "a", protože jinak by měl stejný název jako atribut a VB.NET by to zmátlo. Vraťme se k Module1.vb a zadejme tento parametr do konstruktoru:

Dim kostka As Kostka = New Kostka(10) ' v tuto chvíli se zavolá konstruktor s par. 10
Console.WriteLine(kostka.VratPocetSten())
Console.ReadKey()

Výstup:

Konzolová aplikace
10

Vše funguje, jak jsme očekávali. VB.NET nám již v tuto chvíli nevygeneruje prázdný (tzv. bezparametrický konstruktor), takže kostku bez parametru vytvořit nelze. My to však můžeme umožnit, vytvořme si další konstruktor a tentokrát bez parametru. V něm nastavíme počet stěn na 6, protože takovou hodnotu asi uživatel naší třídy u kostky očekává jako výchozí:

Public Sub New()
    pocetSten = 6
    random = New Random()
End Sub

Zkusme si nyní vytvořit 2 instance kostky, každou jiným konstruktorem (v Module1.vb):

Dim sestistenna As Kostka = New Kostka()
Dim desetistenna As Kostka = New Kostka(10)
Console.WriteLine(sestistenna.VratPocetSten())
Console.WriteLine(desetistenna.VratPocetSten())
Console.ReadKey()

Výstup:

Konzolová aplikace
6
10

VB.NET nevadí, že máme 2 metody se stejným názvem, protože jejich parametry jsou různé. Hovoříme o tom, že metoda New (tedy zde konstruktor) má přetížení (overload). Toho můžeme využívat i u všech dalších metod, nejen u konstruktorů. Visual Studio nám přetížení u metod přehledně nabízí (ve chvíli, kdy za název metody napíšeme levou závorku), variantami metody si můžeme listovat pomocí šipek. Zopakuji že tohoto pomocníka nazval Microsoft IntelliSense. V nabídce vidíme naše 2 konstruktory:

Nápověda IntelliSense k přetíženým metodám v C# - Objektově orientované programování ve Visual Basic .NET

Mnoho metod v .NETu má hned několik přetížení, zkuste se podívat např. na metodu Remove() na Stringu. Je dobré si u metod projít jejich přetížení, abyste neprogramovali něco, co již někdo udělal před vámi. Například metoda WriteLine(), kterou znáte pro vypisování do konzole, má hned 18 variant.

Ukážeme si ještě, jak jde obejít nepraktický název atributu u parametrického konstruktoru (v našem případě aPocetSten) a potom konstruktory opustíme. Problém je samozřejmě v tom, že když napíšeme:

Public Sub New(pocetSten As Integer)
    pocetSten = pocetSten
    random = New Random()
End Sub

VB.NET neví, kterou z proměnných myslíme, jestli parametr nebo atribut. V tomto případě přiřazujeme do parametru znovu ten samý parametr. VS nás na tuto skutečnost dokonce upozorní. Uvnitř třídy se máme možnost odkazovat na její instanci, je uložena v proměnné Me. Využití si můžeme představit např. kdyby kostka měla metodu DejHraci(Hrac hrac) a tam by volala hrac.SeberKos­tku(Me). Zde bychom hráči pomocí Me předali sebe sama, tedy tu konkrétní kostku, se kterou pracujeme. My se tím zde nebudeme zatěžovat, ale využijeme odkazu na instanci při nastavování atributu:

Public Sub New(PocetSten As Integer)
    Me.pocetSten = PocetSten
    random = New Random()
End Sub

Pomocí Me jsme specifikovali, že levá proměnná pocetSten náleží instanci, pravou VB.NET chápe jako z parametru. Máme tedy 2 konstruktory, které nám umožňují tvořit různé hrací kostky. Přejděme dál.

Náhodná čísla

Definujme na kostce metodu hod(), která nám vrátí náhodné číslo od 1 do počtu stěn. Je to velmi jednoduché, metoda bude Public (půjde volat zvenčí) a nebude mít žádný parametr. Návratová hodnota bude typu Integer. Náhodné číslo získáme tak, že na generátoru zavoláme metodu Next(). Ta má několik přetížení:

  • Next(): Varianta bez parametru vrací náhodné číslo v celém rozsahu datového typu int;
  • Next(Do): Vrací nezáporná čísla menší než mez Do. random.Next(100) tedy vrátí číslo od 0 do 99.
  • Next(Od, Do): Vrátí náhodné číslo v zadané mezi, přičemž Od do intervalu patří a Do již ne. Tedy náhodné číslo od 1 do 100 by bylo random.Next(1, 101);

Pro naše účely se nejlépe hodí třetí přetížení, píšeme tedy:

''' <summary>
''' Vykoná hod kostkou
''' </summary>
''' <returns>Číslo od 1 do počtu stěn</returns>
Public Function Hod() As Integer
    Return random.Next(1, pocetSten + 1)
End Function

Dejte si pozor, abyste netvořili náhodný generátor v metodě, která má náhodné číslo vracet, tedy že by se pro každé náhodné číslo vytvořil nový generátor. Výsledná čísla pak nejsou téměř náhodná nebo dokonce vůbec. Vždy si vytvořte jednu sdílenou instanci generátoru (např. do privátního atributu pomocí konstruktoru) a na té potom metodu Next() volejte.

Překrývání metody ToString()

Kostka je téměř hotová, ukažme si ještě jednu užitečnou metodu, kterou ji přidáme a kterou budeme hojně používat i ve většině našich dalších objektů. Řeč je o metodě ToString(), o které jsme se již zmínili a kterou obsahuje každý objekt, tedy i nyní naše kostka. Metoda je určena k tomu, aby vrátila tzv. textovou reprezentaci instance. Hodí se ve všech případech, kdy si instanci potřebujeme vypsat nebo s ní pracovat jako s textem. Tuto metodu mají např. i čísla. Již víme, že ve VB.NET funguje implicitní konverze, jakmile tedy budeme chtít do konzole vypsat číslo nebo kterýkoli jiný objekt, VB.NET na něm zavolá metodu ToString() a vypíše její výstup. Pokud si děláme vlastní třídu, měli bychom zvážit, zda se nám takováto metoda nehodí. Nikdy bychom si neměli dělat vlastní metodu, např. něco jako Vypis(), když máme v VB.NET připravenou cestu, jak toto řešit. U kostky nemá ToString() vyšší smysl, ale u bojovníka bude jistě vracet jeho jméno. My si ji ke kostce stejně přidáme, bude vypisovat, že se jedná o kostku a vrátí i počet stěn. Nejprve si zkusme vypsat do konzole naši instanci kostky:

Console.WriteLine(sestistenna)

Do konzole se vypíše pouze cesta k naší třídě, tedy Arena.Kostka. Metodu nemůžeme jen tak definovat, protože je již definována (v dalších dílech zjistíme proč). Musíme ji tedy přepsat, resp. překrýt. Tím se opět nebudeme nyní podrobně zabývat, nicméně chci, abychom již teď uměli ToString() používat. K překrytí použijeme klíčové slovo Overrides:

''' <summary>
''' Vrací textovou reprezentaci kostky
''' </summary>
''' <returns>Textová prezentace kostky</returns>
Public Overrides Function ToString() As String
    Return String.Format("Kostka s {0} stěnami", pocetSten)
End Function

Nyní opět zkusíme do konzole vypsat přímo instanci kostky.

Výstup:

Konzolová aplikace
Kostka s 6 stěnami

Ještě si naše kostky vyzkoušíme. Zkusíme si v programu s našima dvěma kostkama v cyklech házet a podíváme se, jestli fungují tak, jak se očekává:

' vytvoření
Dim sestistenna As Kostka = New Kostka
Dim desetistenna As Kostka = New Kostka(10)
' hod šestistěnou
Console.WriteLine(sestistenna)
For i As Integer = 0 To 9
    Console.Write(sestistenna.hod() & " ")
Next

' hod desetistenou
Console.WriteLine(vbCrLf)
Console.WriteLine(desetistenna)
For i As Integer = 0 To 9
    Console.Write(desetistenna.hod() & " ")
Next
Console.ReadKey()
' Pokud budete spouštět kód přes náš online kompiler, výsledek
' je udržován v mezipaměti a budou padat stále ta samá čísla.
' S jakoukoli změnou v kódu (např. i přidání komentáře) vyvoláte
' novou kompilace a tedy i vygenerování nových čísel.
Public Class Kostka
    Private random As Random
    Private pocetSten As Integer

    Public Sub New()
        pocetSten = 6
        random = New Random()
    End Sub

    Public Sub New(PocetSten As Integer)
        Me.pocetSten = PocetSten
        random = New Random()
    End Sub

    Public Function Hod() As Integer
        Return random.Next(1, pocetSten + 1)
    End Function

    Public Function VratPocetSten() As Integer
        Return pocetSten
    End Function

    Public Overrides Function ToString() As String
        Return String.Format("Kostka s {0} stěnami", pocetSten)
    End Function

End Class

Výstup může vypadat nějak takto:

Konzolová aplikace
Kostka s 6 stěnami
3 6 6 1 6 3 6 2 6 3

Kostka s 10 stěnami
5 9 9 2 10 4 9 3 10 5

Máme hotovou docela pěknou a nastavitelnou třídu, která reprezentuje hrací kostku. Bude se nám hodit v naší aréně, ale můžete ji použít i kdekoli jinde. Vidíme, jak OOP umožňuje znovupoužívat komponenty.

V následujícím cvičení, Řešené úlohy k 3. lekci OOP ve VB.NET, si procvičíme nabyté zkušenosti z předchozích lekcí.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 336x (63.4 kB)
Aplikace je včetně zdrojových kódů v jazyce VB

 

Předchozí článek
Řešené úlohy k 1.-2. lekci OOP ve VB.NET
Všechny články v sekci
Objektově orientované programování ve Visual Basic .NET
Přeskočit článek
(nedoporučujeme)
Řešené úlohy k 3. lekci OOP ve VB.NET
Článek pro vás napsal Michal Žůrek - misaz
Avatar
Uživatelské hodnocení:
14 hlasů
Autor se věnuje tvorbě aplikací pro počítače, mobilní telefony, mikroprocesory a tvorbě webových stránek a webových aplikací. Nejraději programuje ve Visual Basicu a TypeScript. Ovládá HTML, CSS, JavaScript, TypeScript, C# a Visual Basic.
Aktivity