Implementace seznamu pomocí OOP
Chceme vytvořit abstraktní datový typ seznam.
Naše implementace má mít tu vlastnost, že v každém okamžiku zachovává
uspořádání prvků seznamu. To zajistí metoda vlož, která
zatřídí prvek na správné místo seznamu.
Dále chceme s minimem dalšího programování
vytvářet nové typy seznamů, pro další typy hodnot, které do seznamu
vkládáme. Zde budeme uvažovat pouze typy integer a
string.
V každé z následujících variant je seznam reprezentován třídou, tedy
pro použití seznamu musíme vytvořit její instanci. Potom můžeme
vytvářet libovolné možství různých seznamů (instancí).
Vlastní seznam bude tvořen záznamy:
type ukpol = ^pol;
pol = record
dal: ukpol;
hod: typ_hodnoty;
end;
Od každého seznamu vyžadujeme následujicí metody:
- constructor init
- inicializace na prázdný seznam
- procedure vlož(x:typ_hodnoty)
- vloží prvek (daný jako parametr) do seznamu
- function odeber(n:integer):typ_hodnoty
- odebere n-tý prvek ze seznamu
- procedure vypiš
- vypíše seznam na standardní výstup
Varianta I.
Máme hierarchii tříd seznamů -- pro každý typ vkládané hodnoty jedna třída.
V naše případě máme tedy dvě třídy: seznam_int a
seznam_string.
Typ_hodnoty bude poiter.
V základní třídě seznam_int definujeme další dvě metody,
které nám zajistí znovupoužitelnost ostatních metod, bez jejich
předefinování.
- procedure vypiš_prvek(x:pointer)
- vypíše na standardní výstup hodnotu jednoho prvku, zadaného jako
parametr
Tato metoda je použita v metodě vypiš. Ve svém těle
přetypuje parametr x a vypíše jeho hodnotu.
procedure seznam_int.vypiš_prvek(x:pointer)
begin
writeln(ukinteger(x)^);
end
- function porovnej(x,y:pointer):integer
- porovná hodnoty dvou parametrů a vrací -1/0/1 je-li první
větší/roven/menší než druhý
Tato metoda je použita v metodě vlož, pro správné
zatřídění nového prvku
Obě metody jsou definovány jako virtuální. V odvozených třídách
(seznam_string) předefinovánáme pouze tyto metody. Vše
ostatní je zajištěno dědičností a polymorfismem OOP.
type seznam_string = object(seznam_int)
procedure vypiš_prvek(x:pointer); virtual;
function porovnej(x,y:pointer):integer; virutal;
end;
Varianta II.
Máme pouze jednu třídu seznam a hierarchii tříd prvků, které
do seznamu vkládáme. Typ_hodnoty bude ukprvek, což
je ukazatel na abstraktní třídu prvek, od které jsou odvozeny
všechny další třídy.
Třída prvek obsahuje pouze dvě metody:
- procedure vypiš
- vypíše danou instanci na standardní výstup;
nemá žádný parametr -- hodnota se bere z vlastní instance
- function porovnej(x:ukprvek):integer
- porovná danou instanci s hodnotou parametru a vrací -1/0/1 stejně
jako metoda porovnej v I. variantě.
Protože se jedná o abstarktní třídu, jsou obě metody virtuální a každý
potomek by měl obě metody předefinovat.
V našem případě tedy vytvoříme dvě třídy prvek_int a
prvek_string, obě odvozené od třídy prvek. Každá
třída si definuje nový datový prvek, který nese vlastní hodnotu.
Dále definuje konstruktor, který instanci iniciailzuje podle zadaného
parametru.
type prvek_string = object(prvek)
hods: string;
constructor init(s:string);
procedure vypiš; virutal;
function porovnej(x:ukprvek):integer; virutal;
end;
constructor prvek_string.init(s:string);
begin
hods := s;
end;
procedure prvek_string.vypiš;
begin
writeln(hods);
end;
V metodě porovnej se nevyhneme přetypování, takže bude
obsahovat kód ve tvaru:
if (hods < ukprvek_string(x)^.hod) ....
Varianta III.
Máme hierarchii tříd prvků stejně jako v II. variantě a navíc máme
hierarchii tříd seznamů.
Základní třída seznam definuje metodu vlož tak, že
prvek vkládá na začátek seznamu a tedy vůbec nepoužívá metodu
porovnej instancí jednotlivých prvků. To nám umožňuje
vkládat do seznamu prvky různých typů (jak instance
prvek_int, tak prvek_strign). Vypsání seznamu se
provede správně -- pro každý prvek se volá jemu odpovídající metoda
vypiš.
Od třídy seznam odvodíme třídu seznam_usp, která
pouze předefinuje metodu vlož tak, aby v seznamu byly prvky
pouze jednoho typu. Tj. před vlastním vložením porovná typ nového
prvku s nějakým prvkem seznamu a pokud jsou různého typu, vložení
neprovede.
procedure seznam_usp.vlož(x:ukprvek)
begin
if (typeof(x^) <> typeof(zac^.hod^))
{chyba} ...
else
{vložení}
...
end