Kategória: ObjectPascal

Zmenené: 25. júl 2009

Objektový model Lazarus

Pre úspešné objektové programovanie v Lazarus je potrebné poznať a pochopiť objektový jeho model. Tento objektový model vychádza z objektového modelu Delphi, takže ak ho poznáte, máte vyhraté. Ak ho nepoznáte, čítajte ďalej.

Objektový model Lazarus je založený na objektovom modeli Free Pascalu, doplneného o knižnicu vizuálnych komponentov. Táto knižnica vizuálnych komponentov je nazvaná LCL (Lazarus Component Library) a jej kompletné zdrojové kódy nájdete v adresári lcl svojej inštalácie Lazarus.

Základné pojmy

FreePascal je objektový programovací jazyk, čiže podporuje objektové programovanie. K základným pojmom objektovo orientovaného programovania patria pojmy ako objekt, trieda, dedičnosť, polymorfizmus a zapúzdrenie.

Deklarácia triedy

{ deklaracia triedy }
type
  TNovaTrieda = class
    premenna1: Integer;
    premenna2: String;
    procedure Vypis;
    function Spoj;
end;

Objekty a triedy

Trieda je vlastne akýsi druh deklarácie typu, ktorá popisuje členy, metódy a vlastnosti triedy. Triedu možno deklarovať v rozhraní aj v implementačnej časti jednotky, ale jej metódy musia byť definované v implementačnej časti.

Objekt je dynamická inštancia triedy, ktorá obsahuje hodnoty všetkých členov deklarovaných v triede a v jej predkoch. Objekt je akousi obdobou premennej typu triedy. Pred použitím objektu musí byť deklarovaný a vytvorený. Za vytvorenie a uvoľnenie objektu je zodpovedný programátor.

Deklarácia a vytvorenie objektu

// deklarácia objektu
var myTrieda: TNovaTrieda;

// vytvorenie objektu
myTrieda := TNovaTrieda.Create;

Po tom, ako prestaneme objekt potrebovať, je potrebné ho z pamäte uvoľniť:

myTrieda.Destroy

takéto odstránenie objektu ho síce z pamäte uvoľní, ale teraz objekt myTrieda ukazuje na neplatný popisovač, takže mu treba priradiť hodnotu nil, alebo objekt uvoľňovať pomocou FreeAndNil:

FreeAndNil(myTrieda);

Zložky triedy a objektu

Vnútorná štruktúra triedy a objektu sa podobá na štruktúru typu záznam (record). Jednotlivé zložky objektu sú vlastne premenné, ktoré v sebe nesú informácie o danom objekte. Z hľadiska ich použitia možno tieto premenné rozdeliť na tri typy – členy, metódy a vlastnosti.

Členy

Člen objektu je doslova a do písmena premenná akéhokoľvek typu, ale z pohľadu Objektovo orientovaného programovania je použitie takýchto premenných – členov nesystémové, odporujúce zásadám OOP. Využíva sa len pre súkromné premenné, ktoré nie sú prístupné vonkajšiemu svetu. Identifikátory takýchto súkromných členov je zvykom pomenovávať tak, že začínajú písmenom f. K hodnotám súkromných členov objektov sa potom pristupuje pomocou vlastností.

Metódy

Metódy sú silným nástrojom tried a udávajú čo objekt robí. V podstate sa jedná o premenné procedurálneho typu, čiže vlastne o procedúry a funkcie, ktoré vykonávajú s objektom a jeho stavom nejakú činnosť.

Vlastnosti

Vlastnosti sú špeciálny druh členov a ich úlohou je uchovávať hodnoty premenných a riadiť prístup k nim. Je možné definovať vlastnosti, ktoré sú len na čítanie alebo naopak len na zapisovanie. Hodnotu vlastnosti môže vracať funkcia. Aj zápis do vlastnosti môže byť vykonávaný priamo alebo prostredníctvom metódy.

Dedičnosť

Dedičnosťou je v objektovo orientovanom programovaní nazývaná schopnosť odvodzovať nové triedy od už existujúcich tried. Odvodená trieda potom od existujúcej triedy dedí všetky jej členy, vlastnosti a metódy. Lazarus podporuje len jednoduchú dedičnosť, takže každá trieda môže mať len jedného predka, zvaného základná trieda. Táto základná trieda má zase svoju základnú triedu, atď. Týmto spôsobom triedy dedia členy, vlastnosti a metódy všetkých svojich predchodcov.

Základnou triedou nazývame bezprostredného predchodcu triedy, ktorý je určený v deklarácii triedy. Predchodcom je ktorákoľvek trieda v reťazci dedičnosti, vrátane základnej triedy. Zdedené vlatnosti, členy a metódy je možné prispôsobiť a rozšíriť ďalšími. To umožňuje vytvárať zložité triedy postupným pridávaním metód a vlastností v jednotlivých potomkoch, a tak zvýšiť efektivitu a zjednodušiť vývoj.

Potomok triedy

Type
  TBod = class
    x, y : integer;
    constructor Create(X, Y : integer);
    procedure Nastav_Bod(X, Y: integer);
  end;

  TKruh = class(TBod)
    polomer: integer;
    constructor Create(X, Y, r : integer); // prekrytie konštruktora
    procedure Nastav_Polomer(r: integer);
  end;

V uvedenom príklade deklaruje dve triedy TBod a TKruh a platí v ňom:

  • TKruh je potomkom TBod
  • TBod je základnou triedou pre TKruh
  • TKruh mení konštruktor triedy
  • TKruh pridáva definíciu metódy Nastav_Polomer
  • TKruh dedí od TBod členy x, y a metódu Nastav_Bod

Inými slovami, TKruh zdedil všetky vlastnosti a metódy TBod. Tieto zdedené vlastnosti už nie je potrebné znova definovať, stačí ich používať. Takto stred kruhu nastavíme volaním metódy TKruh.Nastav_Bod(X, Y), ktorá je definovaná v predkovi, teda v triede TBod.

Polymorfizmus

Polymorfizmus (mnohotvárnosť) je to čo objektovému programovaniu pridáva skutočnú silu. Podstata tejto vlastnosti je v mechanizme zdieľania metód, teda že odvodené triedy (potomkovia) môžu nie len používať metódy predka, ale môže aj meniť ich funkčnosť.

Polymorfizmus teda znamená, že meno metódy bude rovnaké v rôznych stupňoch hierarchie tried, ale môže byť pre každú triedu definovaná inak.Zobermesiopäť triedy TBod a jej potomka TKruh .

Prepísané metódy

Type
  TBod = class
    polomer: integer;
    constructor Create(X, Y, r : integer); // prekrytie konštruktora
    procedure Nastav_Bod(X, Y: integer);
    procedure Ukaz; virtual;
    procedure Skry; virtual;
    procedure Posun(dx, dy: Integer);
  end;

  TKruh = class(TBod)
    x, y : integer;
    constructor Create(X, Y : integer);
    procedure Nastav_Polomer(r: integer);
    procedure Ukaz; override;
    procedure Skry; override;
  end;

Mechanizmus posunu je možné definovať v metóde Posun triedy TBod, napríklad najprv volaním metódy Skry, potom zmenou súradníc Nastav_Bod a nakoniec opätovným nakreslením metódou Ukaz:

Metóda TBod.Posun

procedure TBod.Posun(dx, dy:Integer);
begin
    Skry;
    Nastav_Bod;
    Ukaz;
end;

Keďže sú metódy Skry a Ukaz definované ako virtuálne metódy, možno ich správanie zmeniť (nanovo ich definovať) v triede potomka. Takže metóda TKruh.Skry definuje skrytie (zmazanie) nakresleného kruhu a už nie bodu. Obdobne metóda TKruh.Ukaz zabezpečí nakreslenie kruhu.

Možno vás napadá, načo sú nám metódy Skry a Ukaz v triede TBod? Sú zdánlivo zbytočné, pretože nedáva zmysel skrývať a kresliť bod (vo svojej podstate neexistuje). Ale práve ich definícia v tejto triede umožňuje ich použitie v metóde TBod.Posun. A to nám zase umožňuje metódu Posun zdediť v potomkovi, bez toho aby sme ju akokoľvek upravovali. Polymorfizmus sa postará o volanie metód Skry a Ukaz z tej „správnej” triedy, takže metóda Posun bude posúvať kruh, ak je volaná z triedy TKruh a bod pri volaní z triedy TBod.

Zapúzdrenie

Zo zapúzdrením sa stretávame v často i v bežnom živote. Jedná sa o skrytie vlastnej funkcie nejakého stroja (objektu). Dajte si ruku na srdce a odpovedzte úprimne do akej miery viete ako je skonštruovaný Váš diaľkový ovládač? Na druhej strane, potrebujete to vedieť? Nie nepotrebujete, stačí vedieť ktoré gombíky kedy stláčať (rozhranie ovládača).

Zapúzdrenie v objektovo orientovanom programovaní zaručuje, že nikto nemôže priamo pristupovať k vnútru iných objektov. Každý objekt navonok sprítupňuje len rozhranie, pomocou kterého (a nijak inak) možno s objektom pracovať. So zapúzdrením úzko súvisia prístupové úrovne jednotlivých členov, vlastností a metód objektu. V Lazarus možno pracovať so štyrmi úrovňami prístupu:

  • private – súkromné deklarácie - prístup majú len metódy vlastnej triedy a procedúry a funkcie deklarované v rovnakej jednotke,
  • protected – chránené deklarácie - môžu ich využívať metódy vlastnej triedy alebo jej potomkov,
  • public – voľne prístupné deklarácie, na komunikáciu triedy s okolím,
  • published – podobné ako verejné, ale umožňujú spolupracovať s Inšpektorom objektov.

Prístup k metódam a vlastnostiam

type
  TMojaTrieda = class
    private
    { Private declarations }
    protected
    { Protected declarations }
    public
    { Public declarations }
    published
    { Published declarations }
  end;