Funkce, metody a procedury – jaký je mezi nimi rozdíl
Bře/11 3
Všechny tři (funkce, metody i procedury) jsou si poměrně dost podobné – je to pojmenovaná posloupnost příkazů, část programu, kterou můžeme opakovaně volat z jiných částí programu.
Formální pohled
Z formálního hlediska se řídíme názvosloví daného programovacího jazyka.
- Funkce je pojem z funkcionálního programování, vyskytuje se v jazycích jako je JavaScript nebo třeba Haskell.
- Jako metody označujeme funkce v objektově orientovaném programování (OOP), kde dochází k propojení datových struktur a funkčního kódu do objektů. Metody nalezneme v jazycích jako Java, Smalltalk a dalších.
- Procedura je pojem známý z procedurálních jazyků. Nalezneme je např. v Pascalu, ale také v některých databázových systémech – tzv. uložené procedury.
Na funkce, metody a procedury se ale můžeme dívat z věcného hlediska (podle jejich vlastností a smyslu) a odchýlit se od terminologie konkrétního programovacího jazyka.
Funkce
Funkce v programování má velmi blízko k funkcím, jak je chápeme v matematice. Funkce má určitý definiční obor (typ vstupních parametrů) a určitý obor hodnot (typ návratové hodnoty).
Příklad jednoduché funkce v JavaScriptu:
function sečti(a, b) { return a + b; }
V objektových jazycích jako Java máme sice metody a ne funkce, to nám ale nebrání v nich funkce psát:
public static int sečti(int a, int b) { return a + b; }
Přestože sečti()
je formálně metoda (veřejná a statická), ve skutečnosti se jedná o funkci a třída zde plní pouze úlohu jmenného prostoru (společně s názvem balíčku) a nevytváříme její instance (resp. nemusíme). Jedná se o návrhový vzor Knihovní třída.
V Javě najdeme takové funkce např. ve třídě java.lang.Math
. Následující funkce vrací větší ze dvou čísel:
int x = java.lang.Math.max(a, b);
Procedura
Procedura je zvláštním případem funkce – nemá návratovou hodnotu a nemusí mít ani vstupní parametry. Používají se často při dávkovém zpracování – např. každou hodinu zavoláme proceduru, která zpracuje objednávky, které se nashromáždily v databázi, a předá je do jiného systému.
Příklad velmi jednoduché procedury v PostgreSQL, která sečte u dosud nesečtených řádků hodnoty sloupců a
a b
a výsledek uloží do sloupce c
:
CREATE OR REPLACE FUNCTION sčítej() RETURNS void AS $BODY$ UPDATE tabulka_součtů SET c = a + b WHERE c IS NULL $BODY$ LANGUAGE sql VOLATILE;
Tato procedura je napsaná v jazyce SQL – kromě toho můžeme psát plpgsql, který nám umožní tvořit i velmi složité procedury, případně můžeme použít jazyk C či jiný.
Výše uvedená procedura (formálně funkce) nemá žádné vstupní parametry ani návratovou hodnotu, je to prostě jen posloupnost příkazů jazyka, kterou jsme si nějak pojmenovali a uložili.
Zajímavostí je, že procedury můžou mít parametry – a to nejen klasické vstupní, ale i výstupní (nebo vstupně/výstupní). Procedura s výstupním parametrem nám slouží podobně jako funkce – přestože nemá klasickou návratovou hodnotu. Proceduře můžeme např. předat nějaká data a ona nám je upraví.
Takové procedury si můžeme simulovat i v jazyce Java. Mějme nějakou přepravku (strukturu):
public class Osoba { public String jméno; public String příjmení; public String celéJméno; }
A proceduru:
public class UloženéProcedury { public void sestavCeléJméno(Osoba o) { o.celéJméno = o.jméno + " " + o.příjmení; } }
Proceduře předáme data (osobu) a dojde k jejich požadované úpravě. Ovšem pokud programujete tímto stylem v Javě, pravděpodobně děláte něco špatně a připravujete se o hlavní výhody OOP.
Poznámka: pozor ale na předávání hodnotou – pokud uvnitř procedury v Javě přiřadíte do proměnné o
novou osobu, tato změna se mimo danou proceduru nijak neprojeví – původní osoba zůstane netknuta. Můžeme ale pracovat s atributy původní osoby – v takovém případě kód procedury i kód který ji zavolal „vidí“ stejnou instanci osoby.
Metoda
Metody jsou součástí třídy a (pokud nejsou statické) jsou úzce spjaté s danou instancí třídy (objektem). Nejsou to tedy funkce pracující s nějakými globálními proměnnými a daty, ale mají přístup k proměnným dané instance (v tomto případě osoby).
Předchozí příklad můžeme přepsat „objektovějším“ způsobem:
public class Osoba { public String jméno; public String příjmení; public String getCeléJméno() { return jméno + " " + příjmení; } }
Třídu s uloženými procedurami vůbec nepotřebujeme a požadovanou funkcionalitu přesuneme blíže k datům (do třídy Osoba
). Všimněte si, že ani nemusíme ukládat vypočtenou hodnotu celéJméno
– vypočteme ji až ve chvíli, kdy ji někdo bude potřebovat, tzn. zavolá metodu getCeléJméno()
.
Dále změníme přístupnost proměnných z public
na private
a vytvoříme přístupové metody. Zbytek programu totiž nemá zajímat interní implementace dané třídy (jak jsou data uložena), ale jen její rozhraní, API.
public class Osoba { private String jméno; private String příjmení; public String getCeléJméno() { return jméno + " " + příjmení; } public String getJméno() { return jméno; } public String getPříjmení() { return příjmení; } public void setJméno(String jméno) { this.jméno = jméno; } public void setPříjmení(String příjmení) { this.příjmení = příjmení; } }
Tomu se říká zapouzdření. Díky tomu můžeme změnit interní způsob uložení dat (např. neukládat jméno jako řetězec ale jako pole bajtů v určitém kódování) nebo přidat nějaké dodatečné operace prováděné při čtení nebo zápisu hodnot (do metod Něčeho podobného, přestože se to bude jmenovat funkce, můžeme dosáhnout v JavaScriptu – příklad z Wikipedie:
V PostgreSQL metody nenajdeme, ale přesto můžeme dosáhnout určitého propojení dat a operací – byť to nebude jako v OOP. Můžeme využít tzv. spouští (triggerů), které se provedou při operacích nad tabulkou. Pomocí následujícího triggeru a příslušné funkce:
dosáhneme podobného chování jako kdybychom v Javě napsali:
Spouště v databázi můžeme navázat na operace INSERT, UPDATE, DELETE. Ačkoli tabulky nejsou třídy a procedury/funkce nejsou metody, můžeme se částečně přiblížit přístupu používanému v OOP. Přestože každý programovací jazyk má určité paradigma (některé jich mají více), záleží hlavně na programátorovi, jakým stylem bude pracovat. Aneb jak se říká: opravdový programátor umí psát FORTRANské programy v kterémkoliv jazyce :-)get…()
a set…()
// Definice konstruktoru
function auto(znacka, spz) {
this.znacka = znacka;
this.spz = spz;
this.vypisZnacku = function(){alert(this.znacka); };
}
//vytvoření nového auta
var moje_auto = new auto("mercedes", "3A4983");
CREATE OR REPLACE FUNCTION tabulka_součtů_sčítej() RETURNS TRIGGER AS '
BEGIN
new.c := new.a + new.b;
return new;
END;
' LANGUAGE 'plpgsql';
CREATE TRIGGER tabulka_součtů_trigger
BEFORE INSERT ON tabulka_součtů
FOR EACH ROW EXECUTE PROCEDURE tabulka_součtů_sčítej();
public class Součty {
int a;
int b;
int c;
public Součty(int a, int b) {
this.a = a;
this.b = b;
this.c = a + b;
}
}
Závěr
Odkazy a zdroje
V PostgreSQL procedury nejsou
Pavel Stehule10:10 dop. on Březen 17th, 2011
Void funkce jeste neni procedura. Asi nejmarkantnejsi rozdil mezi funkci a procedurou (ze ktereho pak vyplivaji dalsi konsekvence) je ten, ze se funkce vola z prikazu SELECT, kdezto procedura se vola prikazem CALL. V DB2, Oracle, MSSQL maji funkce dost omezenou funkcionalitu (vuci proceduram). V PostgreSQL jsou tato omezeni mensi, jelikoz PostgreSQL nema podporu procedur, ale stale tam jsou - napr. explicitni rizeni vnejsi transakce neni mozne resit uvnitr funkce.
procedura vs. funkce
xkucf0311:11 odpoledne on Březen 17th, 2011
jj, ale to je spíš ten formální pohled – věcně to beru jako proceduru, i když ji budu volat přes SELECT a v terminologii daného systému se to jmenuje funkce. Skutečná funkce je jako filtr na data (vstup→výstup), kdežto procedura jen jako uložená a pojmenovaná posloupnost příkazů.
procedura versus funkce
Pavel Stěhule9:09 odpoledne on Březen 26th, 2011
ona to není formalita - uvnitř SELECTu nelze přerušit posloupnost stransakcí, pokud se blok kódu volá SELECTem, tak musí být dopředu jasné, jak bude vypadat výstup - není možný dynamický resultset nebo nedej Bože multirecordset.