::: Objekt-orienteeritud programmeerimine Borland Delphis

     Autor: Ingmar Tammeväli

Üritan võimalikult lihtsalt anda ülevaate Delphi OOP võimalustest.
 Objekt-orienteeritud programmeerimine on tänapäeva programmeerimises lahutamatu osa (Java,PHP,C++,C#,Delphi jpt); OOP võimaldab ülimalt loetavalt koodi kirjutada, kood pole enam ühes hunnikus, vaid loogiliselt kapseldatud.

Väga asjalik juhend Delphi OOP teemal ka

About.com Delphi programming OOP

Näide 1:

Type

{Loome tavalise baasklassi}

 TSoiduk = class{TObject}
{klasside sees saab määrata ära muutujate / protseduuride nähtavuse}

{private - neid muutujaid ja protseduure saab vaid kasutada omanik class ehk TSoiduk}
{järglasklassid neile muutujatele ligi ei saa}
{Klassi sisesel muutuja nimel võiks olla ees mingi laiend, mis "näitaks", et tegemist klassi sisese muutujaga.
{Mina kasutan selleks (Delphi traditsioonidest tulenevalt) F tähte}

private
 FValjaSoiteKokku : Integer;

{protected - antud sektsiooni meetodeid/muutujaid saavad näevad/saavad kasutada järglasklassid}
protected

{tavaline staatiline meetod:  procedure soida;}
{Kuid kasutades ära OOP ja ülekirjeldamise võimalust ehk ka käitumise muutmist}
{võtame kasutusele direktiivi VIRTUAL väga lihtsalt lahti seletades
 ütleme juba Delphile, et järglasklassis võidakse antud meetod asendada.}

{Virtuaalsete meetodite kasutuselevõtt võimaldab meil kasutada "POLÜMORFISMI"
 st. erinevates (järglas)klassides välja kutsutud (samanimeline) meetod käitub pärimisahelas
 erinevalt.}

{overload direktiiv võimaldab meil klassis kasutada mitut samanimelist meetodit,
ainus erinevus on nende sisendites}

procedure soida;overload;virtual;
{Siin on tegemist keerukama meetodi ülesehitusega;
Me kirjeldame ära meetodi, mida reaalselt antud klassis pole tegelikult olemas;
vaid see kirjeldatakse ära kusagil järglasklassis !
Järgmised 2 meetodit saavad "keha" alles TBuss klassis
Kui kutsuksime välja TAuto klassis ühe neist meetoditest,
saaksime vea "Abstract error", kuna meetod on veel "kehata".}

procedure soida(const marsruut : String);overload;virtual;abstract;

function soidukOnOkonoomne:Boolean;virtual;abstract;

procedure suurendaLoendit;
function     annaValjaSoitudeArv:Integer;

{public - meetodid siin sektsioonis on nähtavad järglasklassidele;
 nende meetodite ja muutujate poole saate pöörduda läbi klassi muutuda}

public

{Tegemist staatilise protseduuriga, mis "elab" isegi siis klassi pole loodud !
Antud võimalust kasutatakse suht harva, kuid tutvustan siiski.
Märkus, sellist liiki protseduurid/funktsioonid ei pääse ligi klassi muutujatele ja proc/func}

class procedure staatilineProtseduur;

{On ka nähtavus published tüüpi, sellest räägime samuti artiklites,
 kus vaatleme Delphi komponendite kirjutamist}

{Need kaks meetodit asuvad heade tavade kohaselt public sektsioonis}
constructor create;{meetod, mis kutsutakse alati välja, kui klass luuakse;}
destructor destroy;override;{meetod, mis kutsutakse välja, kui klass hävitatakse}

End;

{Pärime meetodid eellasklassilt}
TAuto = class(TSoiduk)

protected
{Virtuaalse meetodi uuesti kirjeldamisel, kasutada override direktiivi;
 sest virtuaalse meetodi uuesti kirjeldamisel staatilise meetodiga, hakkab kompilaator pahandama}
 procedure soida;override;
End;

{Märkus: Delphis puudub mitmene pärimine ! välja arvatud INTERFACE objektide korral,
 neist järgmistes artiklites}

TBuss = class(TAuto)
private
 fOkonoomne : Boolean;

private
{property abifunktsioonid}
 function annavaartus: Boolean;
 procedure paneVaartus(const uusvaartus : boolean);

protected
{Märkus !: kui virtuaalse meetodi sisend muutub, on vajalik rakendada parameetrit reintroduce}

 procedure soida(const marsruut : String);reintroduce;
 function soidukOnOkonoomne:Boolean;override;{Siin anname abstraktsele meetodile keha}

public

{!!! Tutvustan ka Delphi komponentide valdkonnast tulnud tehnikat,
kus muutuja väärtustamine toob kaasa mingi sündmuse}
{Need muutujad algavad property klausliga}

property okonoomne : Boolean read annaVaartus write paneVaartus;

 constructor create(const kasOnOkonoomne : boolean);overload;
 constructor create(const kasOnOkonoomne : string);overload;
End;

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

class procedure TSoiduk.staatilineProtseduur;
begin
 showmessage('Suudan isegi siis elada, kui klassi pole loodud !');
end;

{Siin meetodis sooritatakse tavaliselt klassi siseste muutujate algväärtustamine}
constructor TSoiduk.create;
begin

 inherited create; {!!! Siin kutsume välja eellasklassi create meetodi,
 selle koha unustamine põhjustaks programmi valesti toimimist.
 Meie klass pärineb vaikimisi Tobject klassist !}

{Märkus: vaikimise nullitakse klassi loomisel kõik klassi sisesed muutujad,
kuid jällegi heade tavade kohaselt soovitaksin teha muutujate algväärtustamise}

 FValjaSoiteKokku:=0;

end;

{Siin meetodis näiteks: vabastatakse muutujad, mis on loodud create meetodis}
destructor TSoiduk.destroy;
begin

{Siin vabastame muutujad, ntx. kui oleme kusagil klassi sees küsinud mälu}

 inherited destroy; {eellasklassi destroy meetod}

end;

procedure TSoiduk.suurendaLoendit;
begin
 inc(FValjaSoiteKokku);
end;

function TSoiduk.annaValjaSoitudeArv:Integer;
begin
result:=FValjaSoiteKokku;
end;

procedure TSoiduk.soida;
begin
 Self.suurendaLoendit; {Self eesliides ei ole kohustuslik; viitab iseendale}
 showmessage('Sõiduk sõidab');
end;

procedure TAuto.soida;
begin
{Juhul, kui tahaksime ka välja kutsuda ka päritud klassi soida meetodit,
 siis peaksime kirjutama järgnevalt: inherited soida; !}

 suurendaLoendit;
 showmessage('Auto sõidab');
end;

procedure TBuss.soida;
begin
 suurendaLoendit;
 showmessage('Buss sõidab -> marsruut '+marsruut);
end;

function TBuss.soidukOnOkonoomne:Boolean;
begin
 result:=fOkonoomne;
end;

constructor TBuss.create(const kasOnOkonoomne : boolean);
begin
 inherited create;
 fOkonoomne:=kasOnOkonoomne;
end;

constructor TBuss.create(const kasOnOkonoomne : string);
begin
 inherited create;
 fOkonoomne:=kasOnOkonoomne='jah';
end;

{Muutaja okonoomne väärtustamisele reageerivad meetodid}
function TBuss.annavaartus: Boolean;
begin
 result:=fOkonoomne;
 showmessage('Küsime väärtuse ! Siin võiks teha midaiganes');
end;

procedure TBuss.paneVaartus(const uusvaartus : boolean);
begin
  fOkonoomne:=uusvaartus;
 showmessage('Väärtustame muutujat ! Siin võiks teha midaiganes');
end;
......

*** Nüüd kutsume välja baasklassi TSoiduk, millel on järglased TAuto ja TBuss:

# Sooritame lihtsa meetodi väljakutsumise
var pKlass : TSoiduk;
begin
 try
  pKlass:=TSoiduk.create;
   pKlass.soida;
   pKlass.soida;
   pKlass.soida;
   pKlass.soida;
   showmessage(format('Sõitsime %d korda',[pKlass.annaValjaSoitudeArv]));
 finally
   pKlass.destroy;
 end;
end;

# Järgnevalt polümorfismi lihtnäide:

var pKlass : TSoiduk; {!!!}
begin
 try
  pKlass:=TAuto.create;
   {Soovitan jälgida, mis teksti nüüd annab soida meetod välja}

   pKlass.soida;
   pKlass.soida;
   pKlass.soida;
   pKlass.soida;

   showmessage(format('Sõitsime %d korda',[pKlass.annaValjaSoitudeArv]));
 finally
   pKlass.destroy;
 end;
end;

# Näide polümorfismist, abstraktsionismist ja ülekirjeldamisest:

var pKlass : TSoiduk; {!!!}
begin
 try
   {TBuss klassil on nüüd kolm konstruktorit
    eellasklassi oma;boolean tüüpi sisendiga ja string tüüpi sisendiga,
    õiget tüüpi constructori valime vastavalt vajadusele.}

  {pKlass:=TBuss.create;}
  {pKlass:=TBuss.create('jah');}
  pKlass:=TBuss.create(true);

   {pKlass.soida; kutsuks välja eellasklassi meetodi ehk TAuto}
   {TSoidukis kirjeldatud abstraktsed meetodid}
   pKlass.soida('Tallinn-Pärnu');
   pKlass.soida('Tallinn-Pärnu');

   if pKlass.soidukOnOkonoomne then
     showmessage('Sõiduk on ökonoomne');

   showmessage(format('Sõitsime %d korda',[pKlass.annaValjaSoitudeArv]));
 finally
   pKlass.destroy;
 end;
end;

# Näide traditsioonilisest klassi loomisest, ka "property" meetodeid töös

var pKlass : TBuss;
begin
 try

  pKlass:=TBuss.create('jah');

   pKlass.okonoomne:=false;
   if pKlass.okonoomne then showmessage('Siia ei tohiks kunagi jõuda !');
 finally
   pKlass.destroy;
 end;
end;

Polümorfismi saab ka edukalt meetodite sees, kuid see jäägu pisikeseks kodutööks,
vihjeks lõik:

TSoiduk; public sektsioon
procedure kutsuvaljaSoidaMeetod;
begin
 self.soida;
end;

Edukat OOP maailma avastamist !