Programujeme v jazyku C# - Diel 32. - OOP V.

Michal Čižmár  /  24. 08. 2005, 00:00

Toto je posledný diel prvej (a dúfam, že nie poslednej) série článkov o programovaní v jazyku C#. Dnes si objasníme pojmy OOP ako dedičnosť a polymorfizmus. Sú tu dve zlaté pravidlá pri kompozícii tried. Posledných 5 článkov je vhodných na pochopenie OOP aj bez väzby na programovací jazyk.

Toto je posledný diel prvej (a dúfam, že nie poslednej) série článkov o programovaní v jazyku C#. Dnes si objasníme pojmy OOP ako dedičnosť a polymorfizmus. Sú tu dve zlaté pravidlá pri kompozícii tried. Posledných 5 článkov je vhodných na pochopenie OOP aj bez väzby na programovací jazyk.

Všimli ste si aké okrúhle číslo má tento záverečný diel prvej série? :-)))
(Nápoveda: 2^5)

>>this

Na toto slovíčko som skoro zabudol. Je to členská premenná a obsahujú ju vďaka dedičnosti všetky objekty. Je to odkaz na samu seba. :-) Áno, trieda môže takto posiať odkaz na samu seba iným triedam alebo pristupovať k vlastným položkám. Dovolil som si trochu ťažší príklad (možno nie veľmi názorný) predpokladám, že ste už natoľko zdatní programátori, že ho raz dva pochopíte aj v tomto počasí :-)

Príklad 32.1

//---------------------------------------------
using
System;
class
TriedaA 
{
     public int a = 5;
     public TriedaA(TriedaB b)
    {
         b.NastavA(this); //!!This
    }
}

//----------------------------------------------

class
TriedaB
{
      private TriedaA a;
      public void NastavA(TriedaA _a)
     {
          a = _a;
    }
    public void Vypis()
    { //this
        Console.WriteLine(this.a.a);
    }
}

//----------------------------------------------

class
Vystup
{
  public static void Main()
  {
     TriedaB b = new TriedaB();
     TriedaA a = new TriedaA(b);
     b.Vypis();
  }
}
//_==_
//----------------------------------------------

Príklad na stiahnutie: www.inet.sk/download/user/Priklad32.1_this.zip

>>Dedičnosť

nám umožňuje vyššiu úroveň abstrakcie problému. Výrazne sa podieľa na možnosti znovu využitia prog. kódu a zároveň zvyšuje prehľadnosť. Umožňuje “špecializáciu“ už existujúcich tried (bázových).

Príklad :
Predstavte si, že máte napísať program na evidenciu áut. Samozrejme, že vás napadne použiť objekt auto. Ale aký typ auta?? Vytvoríte triedu - predka s menom Auto. Bude obsahovať položku ako napr. ŠPZ, pretože každý typ auta má ŠPZ (aj keď sa mi zdá, že teraz sa to volá inak). Ďalej napr. položku maximálna rýchlosť, pretože každý typ auta má nejakú max. rýchlosť.

Predpokladajme, že ide len o osobné autá, pretože inak by bolo vhodné spraviť ešte ďalšie delenie na osobné či nákladné autá.

Takto sa znázorňuje dedičnosť pomocou UML o ktorom som hovoril v prvom článku z OOP.

         UML model 

>>Ako sa realizuje dedičnosť v C#?
V C# máte oproti C++ obmedzenie, že trieda môže mať len jedného predka. Ak žiadneho neuvediete, je ním automaticky trieda Object, ktorá je bázovou triedou všetkých tried v C#. Potom zdedí všetky položky predka, ak mu to dovolia oprávnenia deklarované v predkovi.

Príklad 32.2
//--------------------------------------------
using
System;
class
Macka
{
    protected float vaha;
    protected float dlzka;
    protected bool chovna = false;
    protected string typ;

   public void VypisTyp()
  {
     Console.WriteLine(typ);
   }
}

//-------------------------------------------

class
MackaDomaca : Macka
{
    private bool maMajitela = true;
    public MackaDomaca()
   {
       vaha = 4.5f;
      dlzka = 40;
      typ = "Macka Domaca";
    }
}

//-----------------------------------------

class
MackaPerzska : Macka
{
    int pocetOceneni = 0;
    int dlzkaChlpov = 10;

   public MackaPerzska()
  {
      vaha = 6.1f;
      dlzka = 60;
      typ = "Macka Perzska";
   }
}

//-----------------------------------------

class
Katalog
{
    public static void Main()
   {
      Macka[] dveMacky = new Macka[2];
      dveMacky[0] = new MackaDomaca();
     dveMacky[1] = new MackaPerzska();

     for(int i = 0; i < 2 ; i++)
        dveMacky[i].VypisTyp();

    }
}
//_==_
//-----------------------------------------

Príklad na stiahnutie:
www.inet.sk/download/user/Priklad32.2_dedicnost.zip


Program vypíše:
Macka Domaca
Macka Perzska

Dedenie sa jednoducho naznačí dvojbodkou za názvom triedy - potomka. Platí, že predok môže vždy zastúpiť potomka. V príklade to vidíte na tom, že som vytvoril pole typu Macka, ale každý prvok som inicializoval iným typom (potomkom).

>>Polymorfizmus

sa dá preložiť ako mnohotvarosť. Jednoducho povedané: Ak má predok aj potomok rovnakú metódu a použijeme deklaráciu typu: Predok a = new Potomok(), ako bude program vedieť, ktorú metódu chceme použiť, či tú z potomka alebo z predka? Asi to najlepšie uvidíte na príklade:

Príklad 32.3

//--------------------------------------------
using
System;
class
Auto
{
     public virtual void Pis()
    {
        Console.WriteLine(" Ja som Auto");
    }
}

//-------------------------------------------

class
Skoda : Auto
{
     public override void Pis()
    {
         Console.WriteLine(" Ja som skodovka");
     }
}

//--------------------------------------------

class
MainClass
{
     public static void Main()
    {
         Auto a1 = new Skoda();
            a1.Pis();
    }
}
//_==_
//-----------------------------------------

Príklad na stiahnutie:
www.inet.sk/download/user/Priklad32.3_polymorfizmus.zip


Ak nepoužijete dvojicu virtual a override tak sa použije metóda z predka a vypíše sa :
Ja som auto
. Ak ale program spustíme tak, ako je uvedení hore, zavolá sa správna metóda z triedy Skoda (vypíše : Ja som škodovka), pretože metóda predka je teraz len virtuálna.

>>Rozhranie

je špeciálny typ triedy, ktorý má deklarované metódy, ale sú bez tela. Dediť môžeme aj niekoľko rozhraní (na rozdiel od čistej dedičnosti). Veľmi jednoducho sa ním implementuje polymorfizmus. Trieda, ktorá zdedí určité rozhranie sa zaväzuje, že implementuje všetky metódy zdedené z rozhrania (napíšete telo k týmto metódam).

Pred meno rozhranie sa zvykne na odlíšenie dávať veľké I.

Príklad 32.4

//--------------------------------------------
using
System;
interface
IDokazeHrat
{
     void Hraj(); // bez tela!!
}

//-----------------------------------------

class
Husle : IDokazeHrat
{
    public void Hraj()
   {
       Console.WriteLine(" Hraju husle");
   }
}

//------------------------------------------

class
Klavir : IDokazeHrat
{
       public void Hraj()
       {
            Console.WriteLine(" Hra klavir");
       }
}

//------------------------------------------

class
Hudobnik
{
    public static void Zahraj(IDokazeHrat nastroj)
    {
          nastroj.Hraj();
    }
   public static void Main()
   {
       Klavir k = new Klavir();
       Husle h = new Husle();

      Zahraj(k);
      Zahraj(h);
  }
}
//_==_
//-----------------------------------------

Príklad na stiahnutie: www.inet.sk/download/user/Priklad32.4_interface.zip
 

Vidíte, že metóda zahraj dokáže akceptovať rôzne typy objektov. Postačujúcou podmienkou, že všetky triedy implementujú rovnaké rozhranie IDokazeHrat.

>>2 zlaté pravidlá pri navrhovaní tried

Niekedy sa vám môže stať, že sa neviete rozhodnúť, či trieda má dediť od inej triedy alebo má tú triedu priamo obsahovať ako členskú premennú. Tieto dve pravidlá som sa naučil kedysi ja a doteraz sa mi vždy osvedčili a ušetrili mi veľa času.

1. JE
pravidlo : trieda A je trieda B. Napr. mackaDomaca je Macka, Skodovka120 je Auto, Stíhačka je Lietadlo. Vtedy je vždy vhodné použiť dedičnosť (A:B), ak môžete na JE pravidlo odpovedať kladne.

2. MÁ
pravidlo : trieda A má triedu B. Napr. : Pocitac má Procesor, Auto má Motor, Lietadlo má Krídlo. Ak na pravidlo odpoviete kladne je dobré, aby trieda A mala ako jednu z členských premenných deklarovanú priamo triedu B a nie je vhodná dedičnosť. Toto sa volá kompozícia tried (skladanie).

>>Iné...

Ak triedu označíte ako sealed, nie je možne z nej dediť. Ak použijete modifikátor abstract, znamená to, že každá metóda je abstraktná. ( V C++ čisto abstraktné triedy, v C# je lepšie použiť rozhranie)

>>Čo bude nabudúce?

Ešte neviem, ale začneme celú novú sériu. Ak ste pochopili všetky doterajšie diely, môžete si povedať, že viete veľmi slušne základy z moderného programovacieho jazyka C#.

Ďakujem Vám za priazeň a čoskoro dovidenia!

>>Predchádzajúce diely

......
......
.....

Michal Čižmár _==_

micitn@orangemail.sk



Neprehliadnite: