Objektumorientált programozás előnyei a kódújrahasznosítás jegyében
Az objektumorientált programozás egyik legfontosabb előnyeként tartjuk számon a kód újrahasznosíthatóságát. A napokban egy fórumban szál formájában itt a weblaboron is terítékre került ez a téma, és többektől elhangzott az a vélemény, hogy ugyanolyan könnyen lehet eljárás központú megközelítéssel újra felhasználható építő kockákat létrehozni, mint az objektumorientált eszközökkel. Ezt a témát járná körül ez a cikk, melynek alapját eredetileg belső oktatási célokra írtam meg egy Sitepointos bejegyzés által indíttatva.
Jelen írásnak nem célja az olvasót bevezetni az OOP-ba, ezért a megértéshez szükséges egy már minimális tudás ezen a területen, de tényleg elég, ha az alapokkal tisztában vagyunk. Ezenkívül szeretném megemlíteni, hogy a cikk elsősorban PHP nyelvre vonatkozik, de megállapításainak többsége egyéb nyelvekre is igaz. Mielőtt kifejezetten a bevezetésben szereplő témát kezdenénk el boncolgatni, a teljesség kedvéért említsük meg az OOP többi alapvető tulajdonságát, és hogy ezek milyen előnyökkel járnak programjaink írása során az eljárás központú megvalósítással szemben.
Programozás szempontjából ennek több előnye is van az eljárás központú megközelítéssel szemben. Először is a különböző program részek közötti kötöttség lényegesen csökkenthető, és ennek biztosítására, kikényszerítésére nyelvi eszközöket is kapunk. Egy modul készítése esetén nem tudjuk elérni, hogy annak felhasználója esetleg nem megfelelő módon alkalmazza, ami inkonzisztens állapothoz vezethet. Egy objektum esetén (a PHP 5-ös verziójától kezdve) szabályozni tudjuk a benne lévő változók és metódusok láthatóságát, biztosítani tudjuk, hogy a programozó az objektumot csak annak felületén keresztül tudja felhasználni.
A fentiből következik egy másik fontos előny is: az osztályunk belső működését bármikor tetszés szerint megváltoztathatjuk, amennyiben biztosított, hogy annak felülete változatlan marad. Ez azt eredményezi, hogy programunk sokkal rugalmasabban és nem utolsó sorban biztonságosabban átalakítható későbbi igények esetén. Például könnyen előfordulhat, hogy hatékonysági szempontok miatt szeretnénk a belső adattárolási formátumot megváltoztatni: OOP esetben csak arra kell figyelnünk, hogy az interfész ne változzon meg, míg procedurális megközelítésben ez jóval nagyobb körültekintést igényel, ráadásul a változtatások akár elsőre nem gondolt programrészekre is hatással lehetnek.
A feladatot korlátozzuk arra, hogy szeretnénk az űrlap elemeit szépen, sorrendben megjeleníteni. Az eljárás központú megvalósítás nagyjából a következő lenne: az elemeket egy tömbben tároljuk, melynek minden egyes elem szintén egy tömb, mely tárolja az adott elem típusát és az egyéb, típusra jellemző adatokat. Minden egyes típushoz tartozik egy őt megjeleníteni képes függvény. Az űrlap megjelenítő eljárásunk a következőképpen nézhetne ki:A fenti kód nem szorul túlzott magyarázatra, ezért nézzünk is meg egy lehetséges OOP megvalósítást.Definiálunk egy
Milyen előnyt jelent ez számunkra? Eljárás központú megközelítésben minden esetben, amikor egy új (übercsászárkirály AJAX-os) elem típust szeretnénk támogatni, akkor módosítanunk kell a
szemléletesebb:Ha egy algoritmus sok callback függvényt igényel, akkor az ilyen irányú megközelítés elég problémássá, nehezen kezelhetővé válik. Sokkal jobb megoldás, ha a funkcionalitást egy osztályba zárjuk, majd a működést befolyásolni képes részeket kihelyezzük egy-egy metódusba, és a késöbbiekben öröklődéssel és ezen függvények felüldefiniálásával érjük el a működés differenciálását.
Nézzük meg például az algoritmusok Hello worldjén, a már előbb is szóbakerült buborék rendezés példáján keresztül, hogy miről is van szó. Körülbelül ez lenne egy tipikus OOP megvalósítás:Ezzel két gond is van:
Ezért érdemes a két dolgot szétbontani.Ez jó példa amúgy a stratégia tervezési mintára is. Tegyük fel, hogy megvalósítunk egyéb rendező algoritmusokat is: ezek mindegyikének lenne egy
Nézzünk egy bonyolultabb, szemléletesebb példát. Feladat: van egy az alábbi felépítéssel bíró szöveg fájlunk (az első sor jelenti a mező neveket):Ebből generáljuk a következő kimenetet:Nézzük a feladat lépéseit:
Alap esetben beolvasnánnk, egy ciklussal végigmegyünk, és kiíratjuk.
Ehelyett nézzük a következő megoldást:Vegyük szemügyre lépésről lépésre.
Mi az előnye ennek a látszólagos elbonyolításnak?
Mindezen szempontokon túl kódunk lényegesen rugalmasabb lesz a későbbi esetleges változtatásokkal szemben.
Mint láthatjuk minimális módosítást kell a programunkon végezni, ráadásul ha jól megnézzük, akkor ezen elemek jó része általánosan használható, tehát ha már egyszer elkészítettük őket, akkor bármikor rendelkezésünkre állnak, bevethetjük őket. Sok apróbb, általánosabb építőelem készítésével, és ezek megfelelő kombinálhatóságával flexibilisebb kódot készíthetünk, mint ha nagyobb, teljesen specializált osztályokat alkalmaznánk. Az objektum kompozició által nyújtott kódújrafelhasználhatóság nem igazán megoldható struktúrális megközelítésben.
Körülbelül ennyit szerettem volna elmondani, remélem, hogy sikerült némileg bizonyítani, hogy az OOP nem egy öncélú, elefántcsont toronyba való szemléletmód, hanem egy nagyon is hasznos, relatíve könnyen "készpénzre" váltható, hatékony eszköz; érdemes némi energiát fektetni a megismerésébe, mert sokkal kifejezőbb, rugalmasabb, könnyebben módosítható programokat fogunk tudni írni alkalmazásával.
■ Jelen írásnak nem célja az olvasót bevezetni az OOP-ba, ezért a megértéshez szükséges egy már minimális tudás ezen a területen, de tényleg elég, ha az alapokkal tisztában vagyunk. Ezenkívül szeretném megemlíteni, hogy a cikk elsősorban PHP nyelvre vonatkozik, de megállapításainak többsége egyéb nyelvekre is igaz. Mielőtt kifejezetten a bevezetésben szereplő témát kezdenénk el boncolgatni, a teljesség kedvéért említsük meg az OOP többi alapvető tulajdonságát, és hogy ezek milyen előnyökkel járnak programjaink írása során az eljárás központú megvalósítással szemben.
Egységbezárás, információ elrejtés
Az egységbezárás (encapsulation) azt jelenti, hogy a procedurális megközelítéssel ellentétben az adatok és a függvények a program nem különálló részét képezik, hanem azok egy egységes egészként jelennek meg, összetartoznak: együtt alkotnak egy objektumot. Az információ elrejtés (information hiding) azt jelenti, hogy az objektum felhasználójának nem kell tudnia arról, hogy az belsőleg hogyan működik, csak azt, hogy milyen funkcionalitást valósít meg, mi a felülete (interface).Programozás szempontjából ennek több előnye is van az eljárás központú megközelítéssel szemben. Először is a különböző program részek közötti kötöttség lényegesen csökkenthető, és ennek biztosítására, kikényszerítésére nyelvi eszközöket is kapunk. Egy modul készítése esetén nem tudjuk elérni, hogy annak felhasználója esetleg nem megfelelő módon alkalmazza, ami inkonzisztens állapothoz vezethet. Egy objektum esetén (a PHP 5-ös verziójától kezdve) szabályozni tudjuk a benne lévő változók és metódusok láthatóságát, biztosítani tudjuk, hogy a programozó az objektumot csak annak felületén keresztül tudja felhasználni.
A fentiből következik egy másik fontos előny is: az osztályunk belső működését bármikor tetszés szerint megváltoztathatjuk, amennyiben biztosított, hogy annak felülete változatlan marad. Ez azt eredményezi, hogy programunk sokkal rugalmasabban és nem utolsó sorban biztonságosabban átalakítható későbbi igények esetén. Például könnyen előfordulhat, hogy hatékonysági szempontok miatt szeretnénk a belső adattárolási formátumot megváltoztatni: OOP esetben csak arra kell figyelnünk, hogy az interfész ne változzon meg, míg procedurális megközelítésben ez jóval nagyobb körültekintést igényel, ráadásul a változtatások akár elsőre nem gondolt programrészekre is hatással lehetnek.
Polimorfizmus, dinamikus kötés
A polimorfizmus általában az OOP-vel ismerkedők számára egy nehezebben megfogható fogalom, ezért közelítsük meg egy példán keresztül. Most jöhetne a sokak által ismerős alakzatok kirajzolása téma, de nem, mi elsősorban webprogramozással foglalkozunk (és mind egyéniségek vagyunk), ezért nézzünk egy testhez állóbb példát: űrlap megjelenítése.A feladatot korlátozzuk arra, hogy szeretnénk az űrlap elemeit szépen, sorrendben megjeleníteni. Az eljárás központú megvalósítás nagyjából a következő lenne: az elemeket egy tömbben tároljuk, melynek minden egyes elem szintén egy tömb, mely tárolja az adott elem típusát és az egyéb, típusra jellemző adatokat. Minden egyes típushoz tartozik egy őt megjeleníteni képes függvény. Az űrlap megjelenítő eljárásunk a következőképpen nézhetne ki:
<?php
function showForm($formItems)
{
foreach($formItems as $item) {
switch($item['type']) {
case 'radio':
showRadio($item);
break;
case 'select':
showSelect($item);
break;
.
.
.
default:
trigger_error('Unsupported form item type!');
}
}
}
?>
<?php
class Form {
function show($formItems)
{
foreach($formItems as $item) {
$item->show();
}
}
}
class FormItemBase {
function show()
{
}
}
class Radio extends FormItemBase {
function show()
{
// Egy radio input mezőnek megfelelő megjelenítő kód
}
}
class Select extends FormItemBase {
function show()
{
// Egy select listának megfelelő megjelenítő kód
}
}
$form = new Form();
$form->show(array(new Radio(), new Select() ...));
?>
Form
és egy FormItemBase
osztályt. Az előbbi show()
metódusa csak annyit csinál, hogy a paraméterül kapott űrlap elemeken (melyek mind a FormItemBase
leszármazottai) végig iterál, és meghívja azok show
tagfüggvényét. A polimorfizmus jelen esetben azt jelenti, hogy a Form
osztály ugyan FormItemBase
elemeket vár, de mi tetszőleges, ebből az osztályból származó elemet átadhatunk, mivel ezek képesek az ősüknek megfelelő módon viselkedni (az ő felületük tartalmazza az ős felületét). A Form
show
metódusa minden esetben az aktuális elem show
metódusát hívja meg, de hogy ez éppen egy Radio
elemé lesz vagy esetleg egy Select
elemé, az csak futásidőben fog eldőlni, ezt nevezzük dinamikus kötésnek.Milyen előnyt jelent ez számunkra? Eljárás központú megközelítésben minden esetben, amikor egy új (übercsászárkirály AJAX-os) elem típust szeretnénk támogatni, akkor módosítanunk kell a
showForm
függvényt, valamint meg kell valósítanunk az adott típusra jellemző kirajzoló eljárást. OOP megközelítésban a Form
osztály show
metódusa érintetlen marad, elegendő csak az új típusnak megfelelő osztályt származtatnunk. El tudtunk készíteni egy általános megjelenítő algoritmust, mely a maga számára szükséges elvárásokat egy alap elem osztály segítségével képes előírni, ezután az utólagos bővítések során már csak az elem specifikus kódokat kell megírnunk.Kód újrahasznosítása
Az objektumorientált környezetben való kód újrahasznosítás különböző lehetőségeit fogjuk szemügyre venni, mindegyik esetben megmutatva, hogy az adott lehetőség milyen módon oldható meg eljárás központú programozás eszközeivel (amennyiben létezik ilyen). Alapvetően három esetet fogunk megvizsgálni.Objektum példányosítás
Ezt tekinthetjük az újrahasznosítás legegyszerűbb módjának. Egy adott funkcionalítást megvalósítunk egy osztályban, majd bármikor szükség esetén létrehozunk belőle egy példányt, és használjuk. Ez alapvetően nem több, mint ha procedurális megközelítésben készítenénk egy modult. Talán az OOP kódszemléletesebb:
query($database, $sql) kontra $database->query($sql)
, de ez erősen személyfüggő.Öröklődés
Az öröklődés során származtatással hozunk létre egy már meglévő osztályból egy újat, amely rendelkezni fog az ős minden tulajdonságával, és nekünk csak a kívánt plusz funkciókat kell megvalósítanunk. A következő pontok ennek tipikus eseteit taglalják.Absztrakt osztály
Absztrakt osztályokkal alapvetően egy felületet definálunk, amlyet a leszármazott osztálynak meg kell valósítani. Ezt is elérhetnénk eljárás központú megközelítésben, de csak úgy, hogy szövegesen dokumentáljuk, hogy egy adott felület megvalósításához milyen függvényeket kell létrehoznunk, a mi felelősségünk, hogy ezt meg is tegyük. Absztrakt osztály használatával ezt már fordítási időben ki tudjuk kényszeríteni. Nem megfelelő implementáció esetén programunk le se fordul, tehát egy plusz nyelvi eszközt kapunk ennek kikényszerítésére.Osztály kibővítése
Ebben az esetben szeretnénk egy már meglévő funkcionalítást valamilyen szempontok alapján kiegészíteni. Eljárás központú megközelítésben is tudunk egy már meglévő modulunkból egy újat létrehozni, de ilyenkor az összes olyan függvényt, ami amúgy megfelelően működik, át kell vezessünk az új modulban egy függvényen keresztül (vagy átnevezgetjük őket, de akkor minden változtatás esetén külön figyelni kell arra, hogy a két modul konzisztens maradjon). OOP esetben ezt sokkal egyszerűbben érjük el az öröklődéssel. Ilyenkor az új osztályban csak azokat a függvényeket kell felüldefiniálni, amelyeknek a működése nem megfelelő számunkra.Callback függvény helyett hook
Procedurális megközelítésben gyakori megoldás, hogy egy függvénynek úgynevezett callback függvényeket adunk át, amellyel előbbi működése annak megváltoztatása nélkül módosítható. Például egy rendező algoritmusnak átadjuk az elemeket összehasonlító függvényt stb..<?php
function bubbleSort(&$array, $compare) {
for ($i = 0, $count = count($array); $i < $count - 1; $i++) {
for ($j = $i; $j < $count; $j++) {
if ($compare($array[$i], $array[$j])) {
$temp = $array[$i];
$array[$i] = $array[$j];
$array[$j] = $temp;
}
}
}
}
function compareIntegers($i, $j) {
return $i > $j;
}
$array = array(8, 2, 4, 3, 1, 9, 7);
bubbleSort($array, 'compareIntegers');
?>
Objektum kompozíció
Ez már az objektumorientált programozás magasabb lépcsőfoka, melynek lényege, hogy olyan osztályokat hozunk létre, melyek működése nem egy konkrét módon történhet, hanem az más osztályokkal paraméterezhető, és használatakor ezekre van szüksége a konkrét feladatának ellátáshoz. Ez által olyan építőelemeket tudunk kialakítani, amelyeket jól kombinálhatunk egymással, és eltérő variációikkal eltérő működést érhetünk el.Nézzük meg például az algoritmusok Hello worldjén, a már előbb is szóbakerült buborék rendezés példáján keresztül, hogy miről is van szó. Körülbelül ez lenne egy tipikus OOP megvalósítás:
<?php
class BubbleSort
{
function BubbleSort(&$array)
{
// algoritmus
}
function compare($i, $j)
{
return $i > $j
}
}
$array = array(8, 2, 4, 3, 1, 9, 7)
$bs = new BubbleSort($array);
?>
- Csak az algoritmus futtatása miatt példányosítanunk kell egy objektumot (melynek nincsenek is tagváltozói).
- Ha felülírjuk a compare metódust egy származtatáskor (más típust rendezni tudó osztályt szeretnénk), akkor fenáll a veszélye, hogy magát az algorimtust is felülírjuk.
Ezért érdemes a két dolgot szétbontani.
<?php
class BubbleSort
{
// Statikus metódus
function sort(&$array, $compareObject) {
// algoritmus
// $compareObject->compare($i, $j);
}
}
class IntCompare
{
function compare($i, $j) {
return $i > $j;
}
}
$array = array(8, 2, 4, 3, 1, 9, 7)
BubbleSort::sort($array, new IntCompare);
?>
compare
metódusa (az ilyen algoritmusokhoz ez általában szükséges), ami az alap OOP megoldást alkalmazva annyi osztályt eredményezne, ahány algoritmusunk van szorozva a rendezendő típusok számával. Kompozíciót használva azonban az osztályok ilyen exponenciális elszaporodása megakadályozható: mindössze szükségünk lesz egy-egy osztályra a különböző fajta rendezési algoritmusokhoz, illetve kell majd egy-egy összehasonlító osztály típusonként, és ezeket szükség szerint, szabadon tudjuk kombinálni.Nézzünk egy bonyolultabb, szemléletesebb példát. Feladat: van egy az alábbi felépítéssel bíró szöveg fájlunk (az első sor jelenti a mező neveket):
---------------8<--------------
category | name | link
PHP | SitePoint | http://www.sitepoint.com
PHP | PHP.net | http://www.php.net
Search | Google | http://www.google.com
Search | HotBot | http://hotbot.lycos.com
---------------8<--------------
<h1>PHP</h1>
<p>
<a href="http://www.sitepoint.com">SitePoint</a>
<br>
<a href="http://www.php.net">PHP.net</a>
</p>
<h1>Search</h1>
<p>
<a href="http://www.google.com">Google</a>
<br>
<a href="http://hotbot.lycos.com">HotBot</a>
</p>
- A fájl tartalmát be kell olvasnunk.
- Végig kell iterálnunk rajtuk
- Ki kell nyomtatnuk őket
Alap esetben beolvasnánnk, egy ciklussal végigmegyünk, és kiíratjuk.
Ehelyett nézzük a következő megoldást:
<?php
Loop::run(
new DataFileIterator(new DataFile('menu.dat', new DataFileReader)),
new MenuPrinter
);
?>
- A
Loop
osztályrun
metódusa első paraméterében kap egy iterátor interfészű objektumot, másodikban pedig egyLoopManipulator
-út, és mindössze annyit tesz, hogy végigiterál az első paraméteren, és minden elemére meghívja aLoopManipulátor
megfelelő eljárásait az alábbiak szerint.<?php class Loop { // statikus function run(&$iterator, &$manipulator) { $index = 0; $iterator->reset(); if ($iterator->isValid()) { $manipulator->prepare(); } for ( ; $iterator->isValid(); $iterator->next()) { $current = &$iterator->getCurrent(); if ($index) { $manipulator->between($index); } $manipulator->current($current, $index++); } if ($index) { $manipulator->finish($index); } return $index; } } ?>
DataFileIterator
osztály egy iterátor felületet biztosít aDataFile
osztályhoz.
- A
DataFile
osztály fájl alapú táblákat képes memóriában tárolni (kb. egy tömb).
- A
DataFileReader
képes a konkrét fájlt feldolgozni, és aDataFile
objektumba belepakolni.
- A
MenuPrinter
pedig kinyomtatja a megfelelő formában a menüt.
4 metódust kell megvalósítania:
prepare()
: iterálás előtt kerül meghívásra
between()
: két elem feldolgozása között kerül meghívásra
current()
: minden elemre meghívásra kerül az iterálás folyamán
finish()
: az utolsó elem feldolgozása után kerül meghívásra
Mi az előnye ennek a látszólagos elbonyolításnak?
- Jól ekülönül az algoritmus (iterálás az elemeken), és a működés (menü nyomtatása).
- Az algoritmust egyszer valósítjuk meg egy általános, újrafelhasználható módon. (Gondoljunk bele, hogy hányszor írunk le egy ehhez hasonló for ciklust.)
- Az egyes elemek újrafelhasználhatóak.
Mindezen szempontokon túl kódunk lényegesen rugalmasabb lesz a későbbi esetleges változtatásokkal szemben.
- Például megváltozik a fájl szerkezete: elég egy új DataFileReader osztályt írnunk.
- Vagy mondjuk a menü bekerül textfájlból adatbázisba:
<?php Loop::run( new QueryIterator( $database->query('select category, name, link from menu, order by category') ), new MenuPrinter ); ?>
Mint láthatjuk minimális módosítást kell a programunkon végezni, ráadásul ha jól megnézzük, akkor ezen elemek jó része általánosan használható, tehát ha már egyszer elkészítettük őket, akkor bármikor rendelkezésünkre állnak, bevethetjük őket. Sok apróbb, általánosabb építőelem készítésével, és ezek megfelelő kombinálhatóságával flexibilisebb kódot készíthetünk, mint ha nagyobb, teljesen specializált osztályokat alkalmaznánk. Az objektum kompozició által nyújtott kódújrafelhasználhatóság nem igazán megoldható struktúrális megközelítésben.
Programtervezési minták
A tervezési minták már némileg túl is mutatnak a kód újrahasznosításon, megoldás újrahasznosítást nyújtanak számunkra amennyiban OO módon programozunk. Ezek olyan kész, kidolgozott receptek, melyeket adott problémák esetében bármikor bátran bevethetünk: ezek az adott feladtra jól bevált, kidolgozott megoldást nyújtanak. Egyik előnyük így adott is, ha felismerjük, hogy adott szituációban egyikük-másikuk használható, akkor egy komoly mankót, kész vázat kapunk az kezünkbe. Ezenkívül egy másik, nem annyira egyértelmű pluszt jelent az, hogy egy egységesen használható fogalom tárat is jelentenek, mely megkönnyíti a fejlesztők közötti kommunikációt.Körülbelül ennyit szerettem volna elmondani, remélem, hogy sikerült némileg bizonyítani, hogy az OOP nem egy öncélú, elefántcsont toronyba való szemléletmód, hanem egy nagyon is hasznos, relatíve könnyen "készpénzre" váltható, hatékony eszköz; érdemes némi energiát fektetni a megismerésébe, mert sokkal kifejezőbb, rugalmasabb, könnyebben módosítható programokat fogunk tudni írni alkalmazásával.
Jó cikk
Számomra kicsit furcsa volt, hogy a cikk ugyan inkább PHP "név" alatt fut, de többször is említed a program befordítását. Nem gond, és értem, miért, csak furcsának hatott.
:)) Én nem, én nem! :)
Elgépelések (a tökéletesség kedvéért):
Szerintem ez a kulcsmondat, ajánlanám mindenki figyelmébe, aki most ismerkedik az OOP-vel. Természetesen lehet nagyobb osztályokba tömöríteni kisebbeket, de a pontos, funkció szerint körülírt osztályok nagy előnyt jelentenek.
Persze ha valaki nagyon kezdő, előbb ismerje meg a nyelvet. Nem Szent Grál az objektumhasználat sem.
köszönöm
Felhő
Még valami
Gábor?
Ezt passzolom, könyvekben láttam már egybe írva is, simán külön írva, mondjuk pont kötőjellel nem rémlik.
Majd Gábor megmondja a tutit. :)
Felhő
Lehet, hogy már megmondta
Egy kis OOP-s helyesírás
Mivel az objektum-orientált kifejezés szerintem egyértelműen egy összetett szó (az orientált utótagja csakis az előtaggal együtt értelmezhető/érthető) és mivel úgy tudom, hogy a 6 szótag a vízválasztó az összetett szavak egybeírásában, ezért (szerintem is) úgy helyes, ahogy legutóbb leírtátok, tehát kötőjellel. Én is így írtam hozzászólásomban - ha jól emlékszem rá - mindenütt.
Helyesbítsetek ki sürgősen, ha sántít az érvelésem! :)
Tényleg, valami jó kis magyar nyelvtannal, helyesírással, egyáltalán nyelvünkkel foglalkozó webes tartalom nem található a neten? Jó lenne...
Objektumorientált, helyesen
Van ilyen a neten:
helyesírás
Szép munka
Érdekes, hogy mostanában mindenki kezd átállni OOP-ra (legalábbis az én környezetemben). Jómagam is most írom első osztályomat, ami a blogom keresőjét képzi majd. Sokáig úgy gondoltam, hogy „Áh, nem értek én még annyira ehhez..”, aztán ismerősöm bíztatására megnéztem, és rájöttem, hogy misem egyszerűbb.
sőt
Jó a cikk, jó az OOP
Igen, én is úgy gondolom, mint Java-fejlesztő, hogy az OOP nyelvek nagyon hasznosak és hatékonyak.
Igazából kicsit megmosolyogtat az, hogy időnként még mindig próbáljuk nagy lendülettel bizonyítani, hogy az OOP-nyelvek tényleg jók és nemcsak valaki vagy valakiknek az agyszüleményei. Szerintem a szoftverpiac illetve annak megoldásai már rég bebizonyították ezt. Illetve ha azt nézem, hogy manapság a két legnépszerűbb és talán leghatékonyabb programozási platform (Java, .NET) alapvetően OOP-alapúak, már semmi többet nem kell mondanom. Szóval az OOP nemcsak marketing-fogás, az biztos!
Ugyanakkor az a meggyőződésem, hogy az objektum-központú programozás nem pusztán osztályok nyakra-főre definiálása. Ugye, a C++ még megengedi a kevert programozási stílus használatát is (objektum-orientált ill. struktúrált programozás), a Java már kényszerít az objektum-orientált szintaxisra. De ez még nem jelenti azt, hogy valóban jól megtervezett, flexibilis, újrahasznosítható programot írunk. Nemcsak szintaktikát kell magunkra kényszerítenünk, hanem egyfajta szemléletmódot is. Lehet, hogy szerencsésebb lenne a jövő programfejlesztőit már csak objektum-orientált programozásra tanítani és egyszerűen kihagyni a struktúrált programozási metodika ismertetését és alkalmazását. Később ugyanis ez nagyon megkötheti az ember gondolkodását…
Nekem nagyon tetszett a Kód újrahasznosítása rész eseteinek számbavétele, egészen a legegyszerűbbtől (a példányosítás) a legbonyolultabbig (objektum-kompozíció). A Java nyelvben az interfészek egy újfajta osztályozást jelenthetnek az elérhető osztályainkon és egy adott interfészen keresztüli elérés, újrafelhasználás is egyik további alesete lehetne ennek a témának, ha nemcsak a PHP-t vennénk figyelembe.
Az is figyelemreméltó szerintem, hogy egyre több beépített dinamikus lehetőséget, megoldást nyújtanak az OOP-nyelvek számunkra. A dinamikus kötés (polimorfizmus) is egyfajta dinamikus szempontot jelent, a dinamikus betöltés (Java-s classloader-ek) is, az egyes tervezési minták szerinti megoldások is sokféle dinamikusságot takarnak és a nyelvi futtató rendszerek (virtuális gépek) sokféle dinamikus jellemzőit is ide sorolnám (szemétgyűjtő technikák, kódoptimalizáló algoritmusok, menedzselt kód stb.).
Köszönet a Szerzőnek, már itt volt az ideje egy új cikknek a weblaboron :)
struktúrált vs OOP
Szerintem itt nem a tanított módszerek kötelmeitől kell tartani. Sok gyakorlással, tapasztalattal és talán képességgel is ugyanaz a szemléletmód kialakítható struktúrált programozási környezetben. Pusztán az a kérdés, h. mennyi időt kell elfecserélni egyik vagy másik metodika szerint kialakított környezettel.
AOP
http://en.wikipedia.org/wiki/Aspect-oriented_programming
mivel már léteznek php-es megoldások is pl.: (ill. lásd wiki-ben)
http://www.phpclasses.org/browse/package/2633.htm
akkutt időhiányban szenvedve sajna nem érek rá közelebről megszemlélni őket, de hátha érdemes lenne :)
link AOP leírásra
Amennyiben...
Én személy szerint köszönöm a cikket!
hiánypótlás
Tetszik
--
Kiskübi
"kerül meghívásra"
Miután egy ilyen cikk a neten lesz az idők végtelenjéig, érdemes lenne az alábbi pár kifejezést kicserélni valamilyen helyes magyar szerkezetre:
# prepare(): iterálás előtt kerül meghívásra
# between(): két elem feldolgozása között kerül meghívásra
# current(): minden elemre meghívásra kerül az iterálás folyamán
# finish(): az utolsó elem feldolgozása után kerül meghívásra
Ilyesmikre gondolok:
iterálás előtti végrehajtás,
két elem feldolgozása között hívódik meg,
minden elemre az iterálás folyamán meghívódik,
az utolsó elem feldolgozása utáni végrehajtás.
kérés
re:kérés
néhány észrevétel
szemléletesebb: query($database, $sql) kontra $database->query($sql), de ez erősen személyfüggő.
...de nem csak, mert az utóbbi szintaktikailag több információt tartalmaz. Az előbbiben három azonosítóra két kategória jut, az utóbbiban pedig három.
Ebben az egész fejezetben nekem nem volt világos, hogy végülis mit kell hook alatt érteni (a szót nem is szerepelteted többet a címen kívül), és hogy ez miben különbözik a callbacktől.
Ez nemcsak a callback fv.-ekre vonatkozik, hanem bármire, vagyis ha egy fv. sok paramétert igényel, akkor csődöl be igazából a hagyományos módszer, s szerintem ez a lényeg. Bár még mindig fennáll a lehetősége annak, hogy struktokban, tömbökben, egyebekben adjuk át az adatokat (l. windows api).
Csak az algoritmus futtatása miatt példányosítanunk kell egy objektumot (melynek nincsenek is tagváltozói).
Ha nem a konstruktorból rendeznél, akkor nem. A második példában már statikus metódussal rendezel, viszont ott ugyanúgy fennáll ez az állítás, csak épp nem a BubbleSort-ot, hanem az IntCompare-t kell példányosítanunk.
Nem értem, miért?
Spec. ezen a sortos példán nem jön jól ki az OOP előnye, valószínűleg mert nincsenek tagváltozók. Miért is jobb ez
ennél?
Igen, csak arra a callback is jó példa.
Kicsit stílust tör. Hát igen, 2006 elején még menő volt fikázni az ajaxot. (Emlékszem, rengeteg ajax-szkeptikus írás jelent meg még kb. egy éve is, azt hiszem, ez már lecsengett.)
interfész
Üdv,
Felhő
re: interfész
Ezért nem is értettem, hogy miért nevezzük hirtelen hooknak a metódusokat...
Tudom, erre írtam a megjegyzésemet. Ha a procedurális programozás függvényhívásai körüli komplikációkról beszélünk, akkor szerintem relevánsabb általában a paraméterek megszaporodását megemlíteni, mint azoknak csak egy részhalmazát (mint ahogy az objektum sem csak metódusokból állhat, hanem mezőkből is).
Rendben, csak szerintem itt már keverednek a szempontok. Kódújrahasznosítás szempontjából speciel nem látom előnyét annak, hogy programnyelvi szinten kezelhetem a láthatóságot, szemben mondjuk egy konvencionális (_ és __) megoldással.
Ugyanaz vonatkozik erre is, mint amit az előbb mondtam. Ez igaz lehet, de kódújrahasznosítás szempontjából nem érzem a relevanciáját.
re: interfész
Üdv,
Felhő