ugrás a tartalomhoz

Objektumorientált programozás előnyei a kódújrahasznosítás jegyében

Hodicska Gergely · 2006. Már. 24. (P), 10.00
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.

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!');
		}
	}
}
?>
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.
<?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() ...));
?>
Definiálunk egy 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ód
szemlé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');
?>
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.

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);
?>
Ezzel két gond is van:
  • 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);
?>
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 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<--------------
Ebből generáljuk a következő kimenetet:
<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>
Nézzük a feladat lépéseit:
  • 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
);
?>
Vegyük szemügyre lépésről lépésre.
  1. A Loop osztály run metódusa első paraméterében kap egy iterátor interfészű objektumot, másodikban pedig egy LoopManipulator-út, és mindössze annyit tesz, hogy végigiterál az első paraméteren, és minden elemére meghívja a LoopManipulá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;
    	}
    }
    ?>
  2. DataFileIterator osztály egy iterátor felületet biztosít a DataFile osztályhoz.
  3. A DataFile osztály fájl alapú táblákat képes memóriában tárolni (kb. egy tömb).
  4. A DataFileReader képes a konkrét fájlt feldolgozni, és a DataFile objektumba belepakolni.
  5. 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.
  1. Például megváltozik a fájl szerkezete: elég egy új DataFileReader osztályt írnunk.
  2. 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.
 
1

Jó cikk

Dualon · 2006. Már. 24. (P), 11.00
Jó cikket írtál, Felhő, összeszedted a fontosabb dolgokat.

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.

és mind egyéniségek vagyunk

:)) Én nem, én nem! :)

Elgépelések (a tökéletesség kedvéért):
  • Ezt a témát járná körül ez a cikk, melyenk alapját
  • A plimorfizmus általában az OOP-vel ismerkedők
  • Absztrakt osztály használatával ezt már fodítási időben
  • ha jól megnézzük, akkor ezen elemk jó része általánosan használható
  • kombinálhatóságával felxibilisebb kódot


Sok apróbb, általánosabb építőelem készítésével, és ezek megfelelő kombinálhatóságával felxibilisebb kódot készíthetünk, mint ha nagyobb, teljesen specializált osztályokat alkalmaznánk.

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.
2

köszönöm

Hodicska Gergely · 2006. Már. 24. (P), 11.10
Elírásokat javítottam, plusz kapott egy képet is szegényke, nem véletlenül ezt. ;).


Felhő
7

Még valami

mefi · 2006. Már. 25. (Szo), 16.35
Tudtommal kötőjellel kell írni, azaz objektum-orientált programozás. :)
8

Gábor?

Hodicska Gergely · 2006. Már. 25. (Szo), 16.43
Szia!


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ő
11

Lehet, hogy már megmondta

mefi · 2006. Már. 26. (V), 17.28
12

Egy kis OOP-s helyesírás

Anonymous · 2006. Már. 26. (V), 18.11
Sziasztok!

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...
13

Objektumorientált, helyesen

Török Gábor · 2006. Már. 26. (V), 19.08
Egyszerű alanyos alárendelő összetételről van szó. Tekintettel a két szó szoros összefonodására, egyben írandó. Javítottam. Az általam septében átfutott szakmai könyvek is így írják. Wikipedia szerint is. Ennek további megvitatására kéretik új téma létrehozása.
18

Van ilyen a neten:

Anonymous · 2006. Már. 29. (Sze), 23.49
http://hu.wikipedia.org/wiki/K%C3%B6t%C5%91jel
21

helyesírás

Fraki · 2007. Nov. 2. (P), 02.54
Hát, a helyesbítés nem túl sürgős, de csak most tévedtem ide. Szóval csak annyit tennék hozzá, hogy szótagszámlálás csak 3 vagy több összetételi tagnál van (ezért hívják 6–3-as szabálynak). Egyébként pedig az AkH. fellelhető a weben.
3

Szép munka

mefi · 2006. Már. 24. (P), 14.11
Gratulálok, szépen összefoglaltad a lényeget. :)
É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.
4

sőt

Anonymous · 2006. Már. 24. (P), 15.44
Sőt, szerintem OOP-val sok mindent még egyszerűbb is megoldani :)
5

Jó a cikk, jó az OOP

Anonymous · 2006. Már. 24. (P), 20.35
Szerintem is nagyon profi és jól összeszedett ez a cikk, s nemcsak elméleti kaland.

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 :)
16

struktúrált vs OOP

gerzson · 2006. Már. 29. (Sze), 23.03
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.


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.
6

AOP

toxin · 2006. Már. 25. (Szo), 11.59
skacok, ha már itt vagyunk, az Aspektus-Orientált-Programozásról (AOP) nemtudnátok párszót szólni, kedves Java programozók előnyben :)

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 :)
14

link AOP leírásra

Marcell · 2006. Már. 27. (H), 19.01
Láttam erről egy cikket anno: http://www.prog.hu/cikkek/905/Aspektus-orientalt+programozas.html
9

Amennyiben...

NetBandita · 2006. Már. 25. (Szo), 21.02
...van köze a témával kapcsolatban nyitott fórumteremnek a cikk megírásához (és a bevezetőből kiderült, hogy van), úgy egy ici-picit hízik a májam. :)

Én személy szerint köszönöm a cikket!
10

hiánypótlás

winston · 2006. Már. 26. (V), 12.28
hohó :) ugyan még nem olvastam végig, de úgy érzem, ennek hiánypótló szerepe van itt, pláne a múltkori topic után. köszönjük. ez -a címek alapján- jó alapot nyújt majd azoknak, akik szeretnék megismerni ezt a szemléletet.
15

Tetszik

Anonymous · 2006. Már. 29. (Sze), 00.51
Nekem is tetszik a cikk, eddigi OOP-s tapasztalatom alapján a színvonalával is meg vagyok elégedve. Köszönjük.

--
Kiskübi
17

"kerül meghívásra"

Anonymous · 2006. Már. 29. (Sze), 23.31
Nagyon jó a cikk! Köszönjük!

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.
19

kérés

Anonymous · 2006. Szep. 15. (P), 00.53
Nem lehetne itt is a css példákra építve egy - kisebb - struktúrált oldal teljes átalakításáról egy példát írni? Szerintem minden - oop kezdőnek - igen hasznos lenne beleértve magamat is.Az oop -t ugyan értem, de gyakorlatban nem igazán megy, szerintem ha nem az alapjaitól kezdenék el egy teljes oldalt, hanem a jelenlegieket szépen lassan átalakítanám akkor jobban belejönnék. Nem tudom ezzel hogy vannak a "többiek".
20

re:kérés

Franczen Attila · 2007. Szep. 20. (Cs), 12.38
Szerintem is jó ötlet volna. Az OOP nagy részét értem, és egy-két, már mások által megírt osztályt magam is használok, ezeket ki is bővítettem, át is írtam itt-ott az igényeim szerint, de ennek ellenére sajnos tény, hogy nem mernék egy éles oldalt OOP-ban írni. Nem tudnám hogyan is kezdjek hozzá. Néha az az érzésem, hogy az a bizonyos szikra hiányzik csak a megértéshez, és megvilágosodáshoz. Talán egy ilyen bemutató után a turbináim felpörögnének :D
22

néhány észrevétel

Fraki · 2007. Nov. 12. (H), 03.27
Csak nemrég jutottam el ehhez a cikkhez, lenne néhány észrevételem.

Talán az OOP kód
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.

Callback függvény helyett hook

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.

Ha egy algoritmus sok callback függvényt igényel, akkor az ilyen irányú megközelítés elég problémássá

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).

Ezzel két gond is van:
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.

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.

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
BubbleSort::sort($array, new IntCompare);

ennél?
bubbleSort($array, intCompare);


Ez jó példa amúgy a stratégia tervezési mintára is.

Igen, csak arra a callback is jó példa.

(übercsászárkirály AJAX-os)

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.)
23

interfész

Hodicska Gergely · 2007. Nov. 14. (Sze), 12.26
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.
Az alatt lévő szövegben van szó arról, hogy a callback helyett jobb, ha a változó részeket egy külön metódusba szervezzuk ki. Ez lenne a hook jelen esetben. De pl. a Drupal is hooknak hívja a maga megoldását arra, hogy bele tudj nyúlni a működésébe, illetve hogy rá tudj akaszkodni bizonyos eseményekre, szóval ez a fogalom nem kötődik az OOP-hez.

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).
Itt nem sima paraméterekről van szó, hanem a működést befolyásoló paraméterekről.

Nem értem, miért?
Kicsit próbálj már meg elvonatkoztatni ettől a példától. Ha engeded, hogy belepiszkálhassanak az objektumod belsejébe tetszőleges módon (ezek a kódok még erősen PHP4es időkben készültek), akkor nem tudod kizárni, hogy úgy módosítsa az osztályodat, hogy ne rontsa el annak a működését. A második esetben viszont már az algoritmushoz nem férsz hozzá, csak különböző összehasonlítást végző osztályokkal tudod paraméterezni azt.

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?
Azért jobb, mert a callback esetében nem tudod előírni, hogy ott milyen függvényt kell átadni, míg a második esetben már igen (persze ez csak PHP5 alatt az igazi), ott egyértelmű, hogy a két osztály milyen "szerződést" köt egymással.

Kicsit stílust tör. Hát igen, 2006 elején még menő volt fikázni az ajaxot.
Abszolút nem volt benne semmi ilyen szándék. :)


Üdv,
Felhő
24

re: interfész

Fraki · 2007. Nov. 14. (Sze), 22.27
szóval ez a fogalom nem kötődik az OOP-hez.

Ezért nem is értettem, hogy miért nevezzük hirtelen hooknak a metódusokat...

Itt nem sima paraméterekről van szó, hanem a működést befolyásoló paraméterekről.

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).

Ha engeded, hogy belepiszkálhassanak az objektumod belsejébe tetszőleges módon (ezek a kódok még erősen PHP4es időkben készültek), akkor nem tudod kizárni, hogy úgy módosítsa az osztályodat, hogy ne rontsa el annak a működését.

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.

Azért jobb, mert a callback esetében nem tudod előírni, hogy ott milyen függvényt kell átadni, míg a második esetben már igen (persze ez csak PHP5 alatt az igazi), ott egyértelmű, hogy a két osztály milyen "szerződést" köt egymá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.
25

re: interfész

Hodicska Gergely · 2007. Nov. 15. (Cs), 12.00
Köszi a kiegészítéseket.


Üdv,
Felhő