Procedurális programozás

A Programozás Wiki wikiből

Procedurális programozásról beszélünk, ha a programozási feladat megoldását egymástól többé kevésbé független alprogramokból (procedure) építjük fel. Az alprogramok általában a programozási nyelvben is jól körülhatárolt formában jelennek meg. Rendszerint egy alprogram feladatát a nevében írjuk le, és a működés pontos feltételeit paraméterként adjuk meg minden alprogramnak minden futtatáskor. Sok esetben az alprogram eredményét egy érték jelzi, amit visszatérési értéknek nevezünk. Egy osztást végző alprogram esetén például az osztandó és az osztó a paraméterek, a hányados pedig a visszatérési érték.

Egy procedurális program futása lényegében hívások és paraméterátadások sorozataként fogható fel. A főprogram meghív egy alprogramot valamilyen paraméterekkel, és annak visszatérési értékei (esetleg az ún. kimeneti paraméterek értékei) függvényében további alprogramokat hívhat meg, amik szintén használhatnak alprogramokat a részfeladatuk elvégzéséhez.

A korábbi (ösztönös, monolitikus) programozási gyakorlatokhoz képest a procedurális programozásnál egy-egy alprogram feladata és paraméterei jól körülhatárolhatók, részben a forráskódban rögzíthetők. Ez a módszer ezért az egyszeri nekifutáshoz képest általában jobban átlátható, könnyebben módosítható kódot eredményez. A forrás mások által is jobban megérthető, későbbi olvasatra is hamarabb felidézhető, mint egy rögtönzött egy-az-egyben megoldás.

Gyakran előfordul, hogy a paraméterek értékeitől elvárjuk, hogy valamilyen tulajdonságnak feleljenek meg (osztásnál például az osztó ne legyen nulla). Az ilyen feltevések összességét az alprogram előfeltételének hívjuk. A paraméterek és a visszatérési érték (vagy kimeneti paraméterek) viszonyát pedig az alprogram utófeltételének nevezzük. Bizonyos írásokban már az összefüggések egy részét is elő- vagy utófeltételnek nevezik. Általában nem bonyolult az elő- és utófeltételek vizsgálata programon belül, néha előfordul, hogy maga a program is vizsgálja azok teljesülését.

A procedurális programozás jól ötvözhető a strukturált programozás eszközeivel. A program gyakran tervezhető úgy, hogy ránézünk a feladatra, és megpróbáljuk részekre bontani. Ha el tudjuk képzelni úgy, mint több részfeladat egymás utáni megoldását, akkor már írhatjuk is rá a programot, ami alprogramok hívásainak szekvenciájaként áll elő. Ha egy alfeladat lényegében egy részfeladat végrehajtása több elemen, az alfeladat kódja a részfeladat hívása egy ciklusban. Ha egyes részfeladatok csak bizonyos esetekben érvényesek, a kódba elágazást kell írnunk a hívás köré. Az építkezést "felülről" indítva számíthatunk arra, hogy azzá fog összeállni a rendszer, amit várunk tőle. "Alulról" építkezve pedig minden pillanatban tudhatjuk, mire vannak már kész eszközeink, és hogyan tudjuk őket összekapcsolni.

A programnyelvekben az alprogramok hívásait, és a paraméterátadást általában vermekkel valósítják meg. Alprogram hívásakor a paraméterek és a jelenlegi hely a veremre kerülnek, alprogram befejezésekor azok eltűnnek, és a hívó fél megkapja a visszatérési értéket. Ez garantálja azt, hogy (amíg a verem meg nem telik) bármelyik alprogramból bármelyik másik hívható, és a vezérlés oda tér vissza, ahonnan az alprogramot hívták. Kedvelt eszköz a rekurzív alprogram-hívás, mivel a forráskód általában jól tükrözi a mögöttes gondolatmenetet.

Példa Pascal-ban:

// név megkérdezése
//    visszatérési érték: személy neve
function Kerdez: String;
begin
   Writeln( 'Hogy hívnak?' );
   ReadLn( Result );
end;

// név ellenőrzése
//    Nev: szemely neve
//    visszatérési érték: engedélyezett-e
function Ellenoriz( Nev: String ): Boolean;
begin
   Result := (Nev+' ')[1] in ['Z','z'];
end;

// név beengedése
//    Nev: személy neve
procedure Beenged( Nev: String );
begin
   Writeln( 'Üdvözöllek, ',Nev,', a klubban.' );
end;

// név elutasítása
//    Nev: személy neve
procedure Elutasit( Nev: String );
begin
   Writeln( 'Ide nem jöhetsz be, ',Nev,'.');
end;

// főprogram
var
   Nev: String;
begin
   Nev := Kerdez;
   if Ellenoriz( Nev )
      then Beenged( Nev )
      else Elutasit( Nev );
end.