Black Friday Black Friday
Black Friday výprodej! Až 80 % extra bodů zdarma! Více informací zde

Cvičení k 14.-16. lekci OOP v C# .NET

C# .NET Objektově orientované programování Cvičení k 14.-16. lekci OOP v C# .NET American English version English version

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

Následující 3 cvičení vám pomohou procvičit znalosti programování v C# .NET z minulých lekcí. Ve vlastním zájmu se je pokuste vyřešit sami. Pod článkem máte pro kontrolu řešení ke stažení. Ale pozor, jakmile se na něj podíváte bez vyřešení příkladů, ztrácí pro vás cvičení smysl a nic se nenaučíte :)

Pokud si opravdu nebudete vědět rady, podívejte se raději znovu do minulých tutoriálů a pokuste se na to přijít.

Jednoduchý příklad

Představte si, že programujete internetový obchod. Vytvořte aplikaci, ve které budou figurovat:

  • zákazníci
  • adresy
  • produkty
  • objednávky

Jednotlivým třídám vymyslete vlastnosti, vytvořte konstruktory a přepište metodu ToString(). Objednávka bude mít referenci na produkt (stačí na jeden) a zákazníka. Zákazník bude mít referenci na fakturační a dodací adresu.

Snad do každého internetového obchodu potřebujeme zaintegrovat platební bránu. Takovou platební bránu nám poskytne nějaká externí společnost, určitě si ji nevyrobíme doma na koleni. Od jejího poskytovatele jsme tedy získali rozhraní, které musí implementovat třída Objednavka v našem obchodu, aby ji bylo možné bránou zaplatit. Rozhraní je následující:

/// <summary>
/// Rozhraní, které jsme dostali od vývojářů platební brány.
/// Implement this interface in your order to be able to send it thru our payment gateway.
/// </summary>
interface IOrder
{
    int Number { get; }
    /// <summary>
    /// Customer first name
    /// </summary>
    string FirstName { get; }
    /// <summary>
    /// Customer last name
    /// </summary>
    string LastName { get; }
    /// <summary>
    /// Street
    /// </summary>
    string Street { get; }
    /// <summary>
    /// House number
    /// </summary>
    int HouseNumber { get; }
    /// <summary>
    /// Registry number
    /// </summary>
    int RegistryNumber { get; }
    /// <summary>
    /// City
    /// </summary>
    string City { get; }
    /// <summary>
    /// Zip code
    /// </summary>
    string Zip { get; }
    /// <summary>
    /// Country
    /// </summary>
    string Country { get; }
    /// <summary>
    /// Product names
    /// </summary>
    string[] Products { get; }
    /// <summary>
    /// Product quantities
    /// </summary>
    int[] Quantities { get; }
    /// <summary>
    /// Product prices
    /// </summary>
    double[] Prices { get; }
}

Vlastnosti jsou:

  • číslo objednávky
  • jméno zákazníka
  • příjmení zákazníka
  • ulice z fakturační adresy zákazníka
  • číslo popisné
  • číslo orientační
  • město
  • PSČ
  • stát
  • pole názvů objednaných produktů
  • pole počtů objednaných produktů
  • pole cen objednaných produktů

Implementujte toto rozhraní ve své třídě Objednavka. Následně vytvořte instanci adresy, zákazníka a testovací objednávky s následujícími daty:

Položka "Body pro ITnetwork.cz" s popisem "Body pro zpřístupnění prémiového obsahu a dosažení vašeho vysněného zaměstnání v IT." s cenou 239 Kč na osobu "Tomáš" "Marný", "Ve Svahu" "10"/"2", "Praha" "10000", "Česká republika".

Přidejte do aplikace třídu Gateway, která zastupuje platební bránu od nějaké firmy. Kód má následující:

/// <summary>
/// Tato třída reprezentuje platební bránu nějakého většího systému třetí strany. V reálu by zde tedy bylo
/// ještě spoustu dalších tříd a metod.
/// </summary>
class Gateway
{
    /// <summary>
    /// Metoda simuluje zpracování objednávky, zde pouze vypsáním do konzole. Důležité je, že díky dodržení
    /// rozhraní od vývojářů platební brány umí brána pracovat s naší objednávkou, i když naši třídu nikdy
    /// neviděli.
    /// </summary>
    /// <param name="order">Objednávka implementující rozhraní IOrder</param>
    public void ProcessOrder(IOrder order)
    {
        Console.WriteLine("Order no. {0}", order.Number);
        Console.WriteLine("=============");
        Console.WriteLine("Name:    {0} {1}", order.FirstName, order.LastName);
        Console.WriteLine("Address: {0} {1}/{2}", order.Street, order.HouseNumber, order.RegistryNumber);
        Console.WriteLine("         {0} {1}", order.City, order.Zip);
        Console.WriteLine("         {0}", order.Country);
        Console.WriteLine();
        for (int i = 0; i < order.Products.Length; i++)
        {
            Console.WriteLine("{0} {1}pcs per {2},-", order.Products[i], order.Quantities[i], order.Prices[i]);
        }
        Console.WriteLine();
        Console.WriteLine("Total price: {0},-", order.Prices.Sum());
    }

}

Pokud jste implementovali správně rozhraní, půjde přes tuto třídu vytisknout vaše objednávka, i když autor třídy vaši třídu Objednavka nikdy neviděl. Máme zde krásnou praktickou ukázku užitečnosti rozhraní :)

Zde je možný kód pro vytvoření objednávky a předání objednávky bráně:

Zakaznik zakaznik = new Zakaznik(1, "Tomáš", "Marný");
Adresa adresa = new Adresa("Ve Svahu", 10, 2, "Praha", "10000");
Produkt produkt = new Produkt("Body pro ITnetwork.cz", "Body pro zpřístupnění prémiového obsahu a dosažení vašeho vysněného zaměstnání v IT.", 239);
Objednavka objednavka = new Objednavka(1, produkt, zakaznik, adresa, adresa);
// Vytvoření brány a předání objednávky bráně
Gateway brana = new Gateway();
brana.ProcessOrder(objednavka);

Ukázka obrazovky programu:

Konzolová aplikace
Order no. 1
=============
Name:    Tomáš Marný
Address: Ve Svahu 10/2
         Praha 10000
         Česká republika

Body pro ITnetwork.cz 1pcs per 239,-

Total price: 239,-

    class Adresa
    {
    }
    class Gateway
    {
    }
    interface IOrder
    {
    }
    class Objednavka: IOrder
    {
    }
    class Produkt
    {
    }
    class Zakaznik
    {
    }

Středně pokročilý příklad

Vytvořte předka reprezentujícího obecný nástroj. Předek bude disponovat vlastnostmi Vaha, Nazev a abstraktní metodou Pracuj(), která nebere žádný parametr a vrací string.

Z nástroje vytvořte potomky Pila, Sroubovak a Kladivo. Kladivo bude mít vlastnost typu bool zda je obouruční. Nástroje budou implementovat metodu Pracuj() tak, že kladivo vypíše do konzole "Zatloukám", šroubovák "Šroubuji" a podobně. Přidejte ještě potomka šroubováku ElektrickySroubovak, který má navíc kapacitu baterie, nastavitelnou v konstruktoru.

V druhé části úkolu vytvořte třídu Bedna, která bude sloužit k uchovávání nářadí. Její vlastností je maximální váha (nosnost, tedy kolik bedna unese) a poté váha nářadí, které je v ní vložené. Implementujte metody pro vložení nástroje do bedny a vyndání nástroje z bedny. Ošetřete, aby se nedal vložit nástroj tak, aby se překročila nosnost bedny. Zamyslete se nad zapouzdřením, kolekce s nářadím nesmí být veřejná, aby se nedal obejít limit nosnosti. Bedně nakonec implementujte metodu pro zjištění celkové hmotnosti obouručních kladiv v ní vložených.

Vaši práci demonstrujte na testovacích datech. Nakonec nechte všechny nástroje v bedně pracovat.

Do bedny s nosností 10000g postupně vložte tyto nástroje v daném pořadí: "Kladívko" (1200 g), "Velké kladivo" (3000 g), "Bourací kladivo" (4000 g), "Šroubovák Philips" (800g), "Zrezivělá pila" (2500 g), "Elektrický šroubovák Bosh" (1800 g). Poté vypište obsah bedny. Výstup by měl být, při správném ošetření maximální hmotnosti, následující:

Konzolová aplikace
Bedna je prázdná.
V bedně je: Kladívko, Velké kladivo, Bourací kladivo, Šroubovák Philips
Zatloukám
Zatloukám
Zatloukám
Šroubuji
Váha obouručních kladiv je 7000 gramů

    class Bedna
    {
    }
    class ElektrickySroubovak : Sroubovak
    {
    }
    class Kladivo : Nastroj
    {
    }
    abstract class Nastroj
    {
    }
    class Pila : Nastroj
    {
    }
    class Sroubovak : Nastroj
    {
    }

Pokročilý příklad

Vytvořte aplikaci, ve které figurují třídy Clovek, který je abstraktním předkem pro třídy Muz a Zena. Člověk má vlastnosti Jmeno, Prijmeni a DatumNarozeni a přetěžuje metodu CompareTo() tak, aby byly jeho instance řazeny podle abecedy a ty se stejným jménem podle data narození.

Člověku přetižte operátor + tak, aby se sečtením dvou lidí opačného pohlaví získal nový člověk (dítě). Nový člověk bude buď Muz nebo Zena, to náhodně vylosujte s pravděpodobností 50:50. Noví muži dostanou jméno "Adam", ženy "Eva" a příjmení po otci, resp. matce. Při sečtení lidí stejného pohlaví získáme hodnotu null.

Vytvořte kolekci následujících lidí:

  • "Karel" "Novák", Narozen 5.2.1988
  • "Josef" "Nový", Narozen 19.3.1978
  • "Jan" "Marek", Narozen 28.4.1968
  • "Karel" "Novák", Narozen 25.6.1958
  • "Marie" "Nová", Narozena 15.8.1988
  • "Věra" "Nováková", Narozena 2.10.1978
  • "Simona" "Mladá", Narozena 8.1.1968
  • "Michaela" "Marná", Narozena 6.12.1958

Kolekci nechte seřadit a následně vytvořte dítě sečtením páru Karel Novák a Marie Nová.

Ukázka obrazovky programu (číslo za jménem je rok narození):

Konzolová aplikace
Jan Marek 68
Josef Nový 78
Karel Novák 58
Karel Novák 88
Marie Nová 88
Michaela Marná 58
Simona Mladá 68
Věra Nováková 78

Karel Novák 88 a Marie Nová 88 spolu mají dítě Eva Nová 17

    public abstract class Clovek : IComparable
    {
    }
    class Muz: Clovek
    {
    }
    class Zena: Clovek
    {
    }

 

Stáhnout

Staženo 189x (167.62 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

 

Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
5 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity (9)

 

 

Komentáře
Zobrazit starší komentáře (6)

Avatar
Michal Gros
Redaktor
Avatar
Michal Gros :29.11.2015 16:15

Taky jsem nad tím přemýšlel, rozhodně bych to tak nenavrhl. Stejně jako nechápu proč bych měl mít člověka s nespárovanou adresou :). Vycházím z toho, že je to rozhraní špatně napsané a musím s ním vytvořit kompatibilní objednávku aby mi fungovala platební brána. Udržovat 3 různá pole kuli jednomu produktu mě děsí :) každé může mít jiný počet prvků. Každopádně všechna pole lze naplnit z jednoho listu produktů.

Odpovědět  +1 29.11.2015 16:15
Jestli jste dobří nahrnou na Vás spoustu práce. Jestli jste sakra dobří, tak se jí dokážete zbavit.
Avatar
Michal Gros
Redaktor
Avatar
Michal Gros :29.11.2015 20:32

Proboha pokaždé když mám pocit, že začínám trochu chápat tak přijde tohle :-O :-)

public static Clovek operator +(Clovek c1, Clovek c2)
        {
            if (c1.GetType() == c2.GetType())
                return null; // Sice je to zajímavé, ale dítě z toho nevznikne
            Muz muz = (c1 is Muz) ? (Muz)c1 : (Muz)c2;
            Zena zena = (c1 is Zena) ? (Zena)c1 : (Zena)c2;
            if (generator.Next(2) == 0) // Pravděpodobnost 1:2
                return new Muz("Adam", muz.Prijmeni, DateTime.Now);
            return new Zena("Eva", zena.Prijmeni, DateTime.Now);
        }

tohle je mi trochu záhadou ? jedná se tzv Podmiňovací operátor (?:) ?

Muz muz = (c1 is Muz) ? (Muz)c1 : (Muz)c2;
Zena zena = (c1 is Zena) ? (Zena)c1 : (Zena)c2;

Může mi to někdo prosím vysvětlit ?

Chápu to dobře, že do proměnné muz přiřadí člověka na pozici C1 pokud je typu muz a pokud C1 není typu muz přiřadí do proměnné muz hodnoty C2 jako muz a obráceně?

Technicky to do proměně muz přiřadí muže a do proměnné zena ženu ať už je kdekoliv na kterékoli pozici ?

public static Clovek operator +(Clovek c1, Clovek c2)
Odpovědět  +1 29.11.2015 20:32
Jestli jste dobří nahrnou na Vás spoustu práce. Jestli jste sakra dobří, tak se jí dokážete zbavit.
Avatar
Ondřej Krsička
Redaktor
Avatar
Odpovídá na Michal Gros
Ondřej Krsička:24.4.2016 13:41

Je to ternární operátor.

 
Odpovědět 24.4.2016 13:41
Avatar
Vrabec853
Člen
Avatar
Vrabec853:13.7.2016 18:29

Co jsem vyčetl, je to něco jako zkrácený if.

Tady je to vysvětlené, a je k tomu i pěkný příklad:

https://msdn.microsoft.com/…y67wk28.aspx

Editováno 13.7.2016 18:31
 
Odpovědět  +2 13.7.2016 18:29
Avatar
Viktor Abel
Člen
Avatar
Viktor Abel:13.11.2016 0:19

Ahoj, ano do pole vkládáme jeden string - a to ten, který je uložený ve vlastnosti produktu Nazev..musí to být pole, aby jsi mohl dát objednávku do parametru metody: public void ProcessOrder(IOrder order) na třídě Gateway-ona s ním pak potřebuje v kódu pracovat jako s polem...

 
Odpovědět  +1 13.11.2016 0:19
Avatar
Marek
Člen
Avatar
Marek:28.6.2017 21:13

Ahoj, omlouvám se za hloupý dotaz, mohl by mi někdo prosím polopatě vysvětlit, jak funguje následující část kódu ?

public IEnumerable<Nastroj> Nastroje
        {
            get { return nastroje.ToArray(); }
        }

Díky, Marek

 
Odpovědět 28.6.2017 21:13
Avatar
klanduch
Člen
Avatar
Odpovídá na Viktor Abel
klanduch:23. března 9:02

Takže ak som to pochopil správne nemôžem dat do pola viac produktov.
Ak nie, ako uložím viac produktov do objednávky ?

 
Odpovědět 23. března 9:02
Avatar
Viktor Abel
Člen
Avatar
Odpovídá na klanduch
Viktor Abel:5. dubna 14:36

Můžeš jich tam dát do toho pole i víc.

 
Odpovědět 5. dubna 14:36
Avatar
Roman Kubik
Člen
Avatar
Roman Kubik:12. září 6:00

Zdravím,
mám zapeklitý problém s funkcí Odevzdat k otestování (Jednoduchý příklad z cvičení k 14.-16.lekci). Pokud příklad spustím na svém počítači ve Visual studio 2017, vše se v pořádku zkompiluje a výstup programu přesně odpovídá zadání - tj. zcela přesně výstupní obrazovce uváděné u zadání, dokonce jsem použil i stejné pojmenování konkrétního zákazníka, zboží atd. Když ale vložím texty jednotlivých tříd, rozhraní a vlastního programu do příslušných oken na stránce a použiji tlačítko "Spustit kód", na stránce se objeví chybové hlášení "...error CS1519: Unexpected symbol '=' in class..." a program se zde nespustí. (Zdrojové texty jsem do stránky kopíroval přímo z mého Visual Studia klasicky = tj. ctrl+c, ctrl+v. Program také nelze odevzdat. Vše jsem procházel a zdrojové texty jsou úplně stejné jako ty v mém Visual Studiu, kde se program bez problémů spustí. Prosím o radu. Děkuji Roman

 
Odpovědět 12. září 6:00
Avatar
Roman Kubik
Člen
Avatar
Roman Kubik:12. září 11:13

Zdravím,
problém jsem už vyřešil. Bylo to zřejmě v zápisu vlastností - např. public int Number { get; private set; }
Mé Visual Studio akceptovalo i zápis public int Number { get; }
Pěkný den!
Roman

 
Odpovědět 12. září 11:13
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 16. Zobrazit vše