Mikuláš je tu! Získaj 90 % extra kreditov ZADARMO s promo kódom CERTIK90 pri nákupe od 1 199 kreditov. Len do nedele 7. 12. 2025! Zisti viac:
NOVINKA: Najžiadanejšie rekvalifikačné kurzy teraz s 50% zľavou + kurz AI ZADARMO. Nečakaj, táto ponuka dlho nevydrží! Zisti viac:

4. diel - Hracia kocka v C# - Zapuzdrenie a konštruktor

V predchádzajúcom cvičení, Riešené úlohy k 1.-3. lekcii OOP v C# .NET, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.

V dnešnom tutoriáli začneme pracovať na sľúbenej aréne, v ktorej budú proti sebe bojovať dvaja bojovníci. Boj bude ťahový (na preskáčku) a bojovník vždy druhému uberie život na základe sily jeho útoku a obrany druhého bojovníka. Simulujeme v podstate stolnú hru, budeme teda simulovať aj hraciu kocku, ktorá dodá hre prvok náhodnosti. Začnime zľahka a vytvorme si dnes práve túto hraciu kocku. Zároveň sa naučíme, ako definovať vlastný konštruktor.

Základné piliere OOP

OOP stojí na troch základných pilieroch:

  • Zapuzdrenie
  • Dedičnosť
  • Polymorfizmus

Dnes použijeme prvý z nich.

Vytvorenie projektu

Vytvorme si novú konzolovú aplikáciu a pomenujme ju Arena. K projektu si pridajme novú triedu s názvom RollingDie. Zamyslime sa nad atribútmi, ktoré kocke dáme. Určite by bolo užitočné, keby sme si mohli zvoliť počet strán kocky (klasicky 6 alebo 10 strán, ako býva zvykom pri tomto type hier). Naša trieda preto bude mať atribút sidesCount. Triedu RollingDie upravíme do nasledujúcej podoby:

/// <summary>
/// Class representing a die for a board game
/// </summary>
class RollingDie
{
     /// <summary>
     /// Number of sides that the die has
     /// </summary>
     public int sidesCount;
}

Konštruktory

Konštruktor je špeciálna metóda, ktorá sa automaticky zavolá pri vytvorení inštancie objektu. Slúži na nastavenie vnútorného stavu objektu a na vykonanie prípadnej inicializácie. Prejdeme do súboru Program.cs, kde kocku vytvoríme týmto spôsobom:

RollingDie die = new RollingDie();

Práve RollingDie() je konštruktor. Pretože v našej triede žiadny nie je, C# si sám vygeneruje prázdny konštruktor. My si však teraz konštruktor do triedy pridáme. Deklaruje sa ako metóda, ale nemá návratový typ a musí mať rovnaký názov ako trieda, v našom prípade teda RollingDie. V konštruktore nastavíme počet strán na pevnú hodnotu.

Prejdeme do súboru RollingDie.cs a pridáme do triedy metódu RollingDie(). V nej nastavíme hodnotu atribútu sidesCount:

/// <summary>
/// Class representing a die for a board game
/// </summary>
class RollingDie
{
    /// <summary>
    /// Number of sides that the die has
    /// </summary>
    public int sidesCount;

    /// <summary>
    /// Initializes a new 6-sided die instance
    /// </summary>
    public RollingDie()
    {
        sidesCount = 6;
    }

}

Presuňme sa do súboru Program.cs a vyskúšajme si vytvoriť kocku a vypísať počet strán:

            RollingDie die = new RollingDie(); // at this point the constructor is called
            Console.WriteLine(die.sidesCount);
            Console.ReadKey();
    class RollingDie
    {
        public int sidesCount;

        public RollingDie ()
        {
            sidesCount = 6;
        }

    }

V konzole vidíme výstup:

Konzolová aplikácia
6

Vidíme, že sa konštruktor naozaj zavolal.

Voliteľný počet strán

My by sme ale chceli, aby sme mohli pri každej kocke pri vytvorení špecifikovať, koľko strán budeme potrebovať. Prejdeme do súboru RollingDie.cs a pridáme konštruktor s parametrom:

public RollingDie(int newSidesCount)
{
    sidesCount = newSidesCount;
}

Všimnime si, že sme pred názov parametra metódy pridali slovo new, pretože inak by mal rovnaký názov ako atribút a C# by to mohlo pomýliť. Vráťme sa do súboru Program.cs a zadáme tento parameter do konštruktora:

            RollingDie die = new RollingDie(10); // at this point the constructor is called with parameter 10
            Console.WriteLine(die.sidesCount);
            Console.ReadKey();
    class RollingDie
    {
        public int sidesCount;

        public RollingDie(int newSidesCount)
        {
            sidesCount = newSidesCount;
        }

    }

V konzole vidíme výstup:

Konzolová aplikácia
10

Všetko funguje tak, ako sme očakávali.

Východisková hodnota kocky

C# nám už v tomto momente negeneruje prázdny (tzv. bezparametrický) konštruktor, takže kocku bez parametra už vytvoriť nemožno. My to však môžeme umožniť, vytvorme si ďalší konštruktor, tentoraz bez parametra. V ňom nastavíme počet strán na 6, pretože takúto hodnotu asi používateľ očakáva ako predvolenú. Prejdeme teda späť do súboru RollingDie.cs a vytvoríme bezparametrický konštruktor:

public RollingDie()
{
    sidesCount = 6;
}

Trieda RollingDie má teda teraz dva konštruktory.

Skúsme si teraz vytvoriť 2 inštancie kocky, každú iným konštruktorom v súbore Program.cs:

            RollingDie sixSided = new RollingDie();
            RollingDie tenSided = new RollingDie(10);
            Console.WriteLine(sixSided.sidesCount);
            Console.WriteLine(tenSided.sidesCount);
            Console.ReadKey();
    class RollingDie
    {
        public int sidesCount;

        public RollingDie()
        {
            sidesCount = 6;
        }

        public RollingDie(int newSidesCount)
        {
            sidesCount = newSidesCount;
        }

    }

Výstup:

Konzolová aplikácia
6
10

Jazyku C# nevadí, že máme dve metódy s rovnakým názvom, pretože ich parametre sú odlišné. Hovoríme tomu, že metóda RollingDie() (teda tu konštruktor) má preťaženie (overload). To môžeme využiť aj pri všetkých ďalších metódach, nielen pri konštruktoroch. Visual Studio nám prehľadne ponúka všetky preťaženia metódy v momente, keď za názov metódy napíšeme ľavú zátvorku. Medzi variantami môžeme listovať pomocou šípok. Tento pomocník sa volá IntelliSense. V ponuke vidíme naše 2 konštruktory:

Pomoc IntelliSense k preťaženým metódam v C# - Objektovo orientované programovanie v C# .NET

Mnoho metód v C# .NET má hneď niekoľko preťažení, skúste sa pozrieť napr. na metódu Remove() na reťazci string. Prezrieť si jednotlivé preťaženia metód je dobré, aby sme neprogramovali niečo, čo už niekto spravil pred nami.

Ukážeme si ešte, ako sa dá obísť nepraktický názov atribútu v parametrickom konštruktore (v našom prípade newSidesCount) a potom sa posunieme ďalej. Problém je v tom, že keď napíšeme:

public RollingDie(int sidesCount)
{
    sidesCount = sidesCount;
}

C# nevie, ktorú premennú myslíme – či parameter, alebo atribút. V tomto prípade priraďujeme do parametra opäť ten istý parameter. Visual Studio nás na túto skutočnosť dokonca upozorní. Vo vnútri triedy však máme možnosť odkazovať sa na jej inštanciu pomocou premennej this. Využitie si môžeme predstaviť napr. keby mala kocka metódu GiveToPlayer(Player player) a tam by volala player.PickUpDie(this). Tu by sme hráčovi pomocou referenčnej premennej this odovzdali samých seba – teda tú konkrétnu kocku, s ktorou pracujeme. My to využijeme iba na nastavenie atribútu:

public RollingDie(int sidesCount)
{
    this.sidesCount = sidesCount;
}

Pomocou premennej this sme špecifikovali, že ľavá premenná sidesCount patrí inštancii, pravú C# chápe ako parameter. Máme teda dva konštruktory, ktoré nám umožňujú vytvárať rôzne hracie kocky. Pokračujme ďalej.

Zapuzdrenie

Zapuzdrenie umožňuje skryť niektoré metódy a atribúty, aby boli prístupné len zvnútra triedy. Objekt si môžeme predstaviť ako čiernu skrinku (blackbox), ktorá má určité rozhranie (interface), cez ktoré jej odovzdávame inštrukcie/dáta a ona ich spracováva.

Nevieme, ako to funguje vnútri, ale vieme, ako sa správa navonok a ako ju používať. Nemôžeme teda spôsobiť chybu, pretože využívame a vidíme len to, čo tvorca triedy sprístupnil.

Príkladom môže byť trieda Human, ktorá má atribút birthDate a na jeho základe ďalšie atribúty: adult a age. Ak by niekto objektu zvonka zmenil birthDate, prestali by platiť premenne adult a age. Hovoríme, že vnútorný stav objektu by bol nekonzistentný. Toto sa nám v štruktúrovanom programovaní môže pokojne stať. V OOP však objekt zapuzdríme – atribút birthDate označíme ako privátny a bude zrejmé, že nechceme, aby ho niekto len tak menil. Navonok sprístupníme metódu ChangeBirthDate(), ktorá nastaví nový dátum narodenia do premennej birthDate a zároveň prepočíta vek a plnoletosť. Použitie objektu je bezpečné a aplikácia zostáva stabilná.

Zapuzdrenie teda núti programátorov používať objekt správne. Rozhranie triedy rozdelíme na verejné (public) a vnútorné (private).

Zapuzdrenie atribútu sidesCount

Predtým sme kvôli jednoduchosti nastavovali všetky atribúty triedy ako public, teda verejné. Väčšinou to však nechceme – zvyčajne použijeme private, aby sa nedali zmeniť zvonka. Atribút je potom viditeľný len vo vnútri triedy a zvonka C# predstiera, že neexistuje. Pri návrhu triedy teda nastavíme všetko na private a až keď niečo skutočne potrebujeme sprístupniť, použijeme public. Naša trieda teraz vyzerá takto:

/// <summary>
/// Class representing a die for a board game
/// </summary>
class RollingDie
{
    /// <summary>
    /// Number of sides that the die has
    /// </summary>
    private int sidesCount;

}

Teraz už nikto nemôže zmeniť počet strán u vytvorenej kocky. Počet strán však môžeme umožniť prečítať. V súbore RollingDie.cs pridáme metódu GetSidesCount(), ktorá vráti hodnotu atribútu sidesCount. Dosiahli sme tým, že atribút je v podstate iba na čítanie (read-only). Nová metóda bude vyzerať asi takto:

/// <summary>
/// Returns the number of sides the die has
/// </summary>
/// <returns>Number of sides the die has</returns>
public int GetSidesCount()
{
     return sidesCount;
}

Presuňme sa do súboru Program.cs a upravme výpis počtu strán tak, aby využíval novú metódu:

            RollingDie sixSided = new RollingDie();
            RollingDie tenSided = new RollingDie(10);
            Console.WriteLine(sixSided.GetSidesCount());
            Console.WriteLine(tenSided.GetSidesCount());
            Console.ReadKey();
    class RollingDie
    {
        private int sidesCount;

        public RollingDie()
        {
            sidesCount = 6;
        }

        public RollingDie(int sidesCount)
        {
            this.sidesCount = sidesCount;
        }

        public int GetSidesCount()
        {
            return sidesCount;
        }

    }

Po spustení programu v konzole vidíme výstup:

Konzolová aplikácia
6
10

V nasledujúcej lekcii, Hracia kocka v C# druhýkrát - Prekrývanie metód a random, sa naučíme prekrývať metódy, pracovať s náhodnými číslami a dokončíme hraciu kocku.


 

Mal si s čímkoľvek problém? Zdrojový kód vzorovej aplikácie je k stiahnutiu každých pár lekcií. Zatiaľ pokračuj ďalej, a potom si svoju aplikáciu porovnaj so vzorom a ľahko opráv.

Predchádzajúci článok
Riešené úlohy k 1.-3. lekcii OOP v C# .NET
Všetky články v sekcii
Objektovo orientované programovanie v C# .NET
Preskočiť článok
(neodporúčame)
Hracia kocka v C# druhýkrát - Prekrývanie metód a random
Článok pre vás napísal David Hartinger
Avatar
Užívateľské hodnotenie:
26 hlasov
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David sa informačné technológie naučil na Unicorn University - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity