NOVINKA: Získej 40 hodin praktických dovedností s AI – ZDARMA ke každému akreditovanému kurzu!

Lekce 4 - Hrací kostka v C# - Zapouzdření a konstruktor

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

V dnešním tutoriálu začneme pracovat na slíbené aréně, ve které budou proti sobě bojovat dva bojovníci. Boj bude tahový (na př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.

Základní pilíře OOP

OOP stojí na základních třech pilířích:

  • Zapouzdření
  • Dědičnost
  • Polymorfismus

Dnes použijeme první z nich.

Vytvoření projektu

Vytvořme si novou konzolovou aplikaci a pojmenujme ji Arena. K projektu si přidejme novou třídu 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). Naše třída proto bude mít atribut pocetSten. Třídu Kostka upravíme do následující podoby:

/// <summary>
/// Třída reprezentuje hrací kostku
/// </summary>
class Kostka
{
    /// <summary>
    /// Počet stěn kostky
    /// </summary>
    public int pocetSten;

}

Konstruktory

Konstruktor je speciální metoda, která se sama zavolá ve chvíli vytvoření instance objektu. Slouží k nastavení vnitřního stavu objektu a k provedení případné inicializace. Přejdeme do souboru Program.cs, kde kostku vytvoříme tímto způsobem:

Kostka kostka = new Kostka();

Právě Kostka() je konstruktor. Protože v naší třídě žádný není, C# si sám vygeneruje prázdný konstruktor. 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 stejný název jako je název třídy, v našem případě tedy Kostka. V konstruktoru nastavíme počet stěn na pevnou hodnotu.

Přejdeme do souboru Kostka.cs a přidáme do třídy metodu Kostka(). V ní nastavíme hodnotu atributu pocetSten:

/// <summary>
/// Třída reprezentuje hrací kostku
/// </summary>
class Kostka
{
    /// <summary>
    /// Počet stěn kostky
    /// </summary>
    public int pocetSten;

    /// <summary>
    /// Vytvoří novou instanci hrací kostky
    /// </summary>
    public Kostka()
    {
        pocetSten = 6;
    }

}

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

            Kostka kostka = new Kostka(); // v tuto chvíli se zavolá konstruktor
            Console.WriteLine(kostka.pocetSten);
            Console.ReadKey();
    class Kostka
    {
        public int pocetSten;

        public Kostka()
        {
            pocetSten = 6;
        }

    }

V konzoli vidíme výstup:

Konzolová aplikace
6

Vidíme, že se konstruktor opravdu zavolal.

Volitelný počet stěn

My bychom ale chtěli, abychom mohli u každé kostky při vytvoření specifikovat, kolik stěn budeme potřebovat. Přejdeme do souboru Kostka.cs a dáme tedy konstruktoru parametr:

public Kostka(int novyPocetSten)
{
    pocetSten = novyPocetSten;
}

Všimněme si, že jsme před název parametru metody přidali slovo novy, protože jinak by měl stejný název jako atribut a C# by to zmátlo. Vraťme se do souboru Program.cs a zadejme tento parametr do konstruktoru:

            Kostka kostka = new Kostka(10); // v tuto chvíli se zavolá konstruktor s par. 10
            Console.WriteLine(kostka.pocetSten);
            Console.ReadKey();
    class Kostka
    {
        public int pocetSten;

        public Kostka(int novyPocetSten)
        {
            pocetSten = novyPocetSten;
        }

    }

V konzoli vidíme výstup:

Konzolová aplikace
10

Vše funguje tak, jak jsme očekávali.

Výchozí hodnota kostky

C# nám již v tuto chvíli nevygeneruje prázdný (tzv. bezparametrický) konstruktor, takže kostku bez parametru již 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í. Přejdeme tedy zpátky do souboru Kostka.cs a vytvoříme konstruktor bez parametru:

public Kostka()
{
    pocetSten = 6;
}

Třída Kostka má tedy nyní dva konstruktory.

Zkusme si nyní vytvořit 2 instance kostky, každou jiným konstruktorem v souboru Program.cs:

            Kostka sestistenna = new Kostka();
            Kostka desetistenna = new Kostka(10);
            Console.WriteLine(sestistenna.pocetSten);
            Console.WriteLine(desetistenna.pocetSten);
            Console.ReadKey();
    class Kostka
    {
        public int pocetSten;

        public Kostka()
        {
            pocetSten = 6;
        }

        public Kostka(int novyPocetSten)
        {
            pocetSten = novyPocetSten;
        }

    }

Výstup:

Konzolová aplikace
6
10

Jazyku C# nevadí, že máme dvě metody se stejným názvem, protože jejich parametry jsou různé. Hovoříme o tom, že metoda Kostka() (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řehledně nabízí všechny přetížení u metody ve chvíli, kdy za název metody napíšeme levou závorku. Variantami metody můžeme listovat pomocí šipek. Tohoto pomocníka nazval MS 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í v C# .NET

Mnoho metod v C# .NET má hned několik přetížení, zkuste se podívat např. na metodu Remove() na řetězci string. Projít si jednotlivá přetížení u metod je dobré proto, abychom neprogramovali něco, co již někdo udělal před námi.

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

public Kostka(int pocetSten)
{
    pocetSten = pocetSten;
}

C# 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 však máme možnost odkazovat se na její instanci, která je uložena v proměnné this. Využití si můžeme představit např. kdyby kostka by měla metodu DejHraci(Hrac hrac) a tam by volala hrac.SeberKostku(this). Zde bychom hráči pomocí referenční proměnné this předali sebe sama, tedy tu konkrétní kostku, se kterou pracujeme. My se tímto zde nebudeme zatěžovat, ale využijeme odkaz na instanci při nastavování atributu:

public Kostka(int pocetSten)
{
    this.pocetSten = pocetSten;
}

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

Zapouzdření

Zapouzdření umožňuje skrýt některé metody a atributy tak, aby zůstaly použitelné jen pro třídu zevnitř. Objekt si můžeme představit jako černou skříňku (anglicky blackbox), která má určité rozhraní (interface), přes které jí předáváme instrukce/data a ona je zpracovává.

Nevíme, jak to uvnitř funguje, ale víme, jak se to navenek chová a používá. Nemůžeme tedy způsobit nějakou chybu, protože využíváme a vidíme jen to, co tvůrce třídy zpřístupnil.

Příkladem může být třída Clovek, která bude mít atribut datumNarozeni a na jeho základě další atributy: plnolety a vek. Kdyby někdo objektu zvenčí změnil datumNarozeni, přestaly by platit proměnné plnolety a vek. Říkáme, že vnitřní stav objektu by byl nekonzistentní. Toto se nám ve strukturovaném programování může klidně stát. V OOP však objekt zapouzdříme a atribut datumNarozeni označíme jako privátní a tím pádem bude jasné, že nechceme, aby nám jej někdo jen tak měnil. Naopak ven vystavíme metodu ZmenDatumNarozeni(), která dosadí nové datum narození do proměnné datumNarozeni a zároveň provede potřebný přepočet věku a přehodnocení plnoletosti. Použití objektu je bezpečné a aplikace zůstává stabilní.

Zapouzdření tedy tlačí programátory používat objekt jen tím správným způsobem. Rozhraní (interface) třídy rozdělí na veřejně přístupné (public) a vnitřní strukturu (private).

Zapouzdření atributu pocetSten

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 C# tváří, že vůbec neexistuje. Při návrhu třídy tedy nastavíme vše na private a pouze v případě, že něco bude opravdu potřeba vystavit, použijeme public. Naše třída nyní vypadá takto:

/// <summary>
/// Třída reprezentuje hrací kostku
/// </summary>
class Kostka
{
    /// <summary>
    /// Počet stěn kostky
    /// </summary>
    private int pocetSten;

}

Nyní nám nebude moci nikdo u již vytvořené kostky měnit počet stěn. Umožníme však počet stěn zvenku přečíst. V souboru Kostka.cs přidáme do třídy 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). Nová metoda bude vypadat asi takto:

/// <summary>
/// Vrátí počet stěn hrací kostky
/// </summary>
/// <returns>počet stěn hrací kostky</returns>
public int VratPocetSten()
{
    return pocetSten;
}

Přesuňme se do souboru Program.cs a upravme výpis počtu stěn na použití nové metody:

            Kostka sestistenna = new Kostka();
            Kostka desetistenna = new Kostka(10);
            Console.WriteLine(sestistenna.VratPocetSten());
            Console.WriteLine(desetistenna.VratPocetSten());
            Console.ReadKey();
    class Kostka
    {
        private int pocetSten;

        public Kostka()
        {
            pocetSten = 6;
        }

        public Kostka(int pocetSten)
        {
            this.pocetSten = pocetSten;
        }

                public int VratPocetSten()
                {
                        return pocetSten;
                }

    }

Po spuštění programu v konzoli vidíme výstup:

Konzolová aplikace
6
10

V příští lekci, Hrací kostka v C# podruhé - Překrývání metod a random, se naučíme překrývat metody, pracovat s náhodnými čísly a dokončíme hrací kostku.


 

Měl jsi s čímkoli problém? Zdrojový kód vzorové aplikace je ke stažení každých pár lekcí. Zatím pokračuj dál, a pak si svou aplikaci porovnej se vzorem a snadno oprav.

Předchozí článek
Řešené úlohy k 1.-3. lekci OOP v C# .NET
Všechny články v sekci
Objektově orientované programování v C# .NET
Přeskočit článek
(nedoporučujeme)
Hrací kostka v C# podruhé - Překrývání metod a random
Článek pro vás napsal David Hartinger
Avatar
Uživatelské hodnocení:
681 hlasů
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 se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity