|
Ü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 !
|