ugrás a tartalomhoz

PHP OPP

imdawe · 2011. Feb. 8. (K), 07.19
Üdv!

Interfészek és az Absztrakt osztályok tanulmányozásával vagyok elakadva.
Minden tiszta kivétel az hogy most az interfészek arra jók hogy megszabjuk egy származtatott osztálynak a metódusait se több se kevesebb? Eddig ezt így vettem ki.
Az absztrakt osztályoknak pedig a metódusait hogy használni tudjuk előbb definiálni kell egy származtatott osztályban ha jól értettem?
Azért gondolom hogy ez rossz így mert nem sok értelmét látom, és szeretném előbb megérteni mielőtt neki állok a kódokkal bajlódni hogy is működik : )
 
1

Szerintem ezekre a dolgokra

neogee · 2011. Feb. 8. (K), 08.21
Szerintem ezekre a dolgokra és ezek értelmére igazán akkor fogsz rájönni, amikor majd beleütközöl azokba a "problémákba" amikre általában használni szoktuk őket.

Én special az absztrakt osztályokat akkor használom, amikor két különböző osztálynak van néhány azonos tulajdonsága és viselkedése és ezeket szeretném kiemelni egy közös ősbe, de ugyanakkor a gyerek osztályok kiegészítő tulajdonságai és viselkedései nélkül értelmetlen lenne az ős működése, vagy éppen nem szeretném, hogy az ős önmagában példányosítható legyen.

Fontso különbség az absztract osztály és az interface között, hogy az absztract osztály tartalmazhat implementációs részt a metódusokra nézve, míg az interface, csak az osztály felületét határozza meg.

Interfacet akkor célszerű használni, mikor van egy osztályod ami egy másik osztályba tartozó objektumot vár és azzal dolgozik, de tulajdonképpen neked baromira mindegy hogy azaz objektum milyen osztályba tartozik, csupán az a fontos, hogy egy bizonyos meghatározott interface legyen amit kezelni tudsz.

Azt hiszem valami ilyesmi. :)
2

Példa:

neogee · 2011. Feb. 8. (K), 08.44

class abstract_ClassInfo {

	public function info() {
		return get_class( $this );
	}

}

class A extends abstract_ClassInfo {

	public function some_method() {
		// do something
	}

}

class B extends abstract_ClassInfo {

	public function some_method() {
		// do something else
	}

}
Ennél a példánál A és B osztályok teljesen mást csinálnak, más metódusaik vannak, más osztályváltozóik stb... De mi szeretnénk, ha mindkettőről ki tudnánk iratni bizonyos infókat az adott osztályról.Nyilvánvaló, hogy ezt a működést egy közös ősben kell definiálni és az is nyilvánvaló, hogy egy olyan osztálynak ami csak annyit csinál, hogy kiirja magáról az infókat nem sok értelme lenne.
Persze ez egy nagyon primitív példa, és értelme sem sok van, de jól látszik, hogy mire lehet használni az absztrakt osztályokat.

<?php

interface infoInterface {

	public function info();

}

class A implements infoInterface {

	public function info() {
		return get_class( $this );
	}
	
	// some other methods

}

class B implements infoInterface {

	public function info() {
		return implode(',',get_class_methods( get_class( $this ) ));
	}

	public function some_method() {
		// do something
	}

}

class C {

	public function display_info( $object ) {
		print $object->info();
	}

}

$c = new C();
$c->display_info( new A() );
$c->display_info( new B() );

?>
Itt pedig láthatod, hogy annak ellenére, hogy A és B teljesen különböző osztály, mást csinálnak és még magát az info methodust is másképpen implementálják, annak ellenére az interface segítségével biztosítani tudtuk, hogy a C osztályunk képes legyen ugyanúgy kezelni mindkét osztályba tartozó objektumokat. Az interface tulajdonképpen csak annyit mond meg, hogy osztálynak milyen elérési felülete kell hogy legyen. Annak megvalósítását az adott osztályra bízza.
3

Plusz én még megemlíteném azt

Protezis · 2011. Feb. 8. (K), 08.55
Plusz én még megemlíteném azt is, hogy PHP-ben nincs többszörös öröklődés, viszont egy osztály több interfészt is implementálhat és kezelheted azt bármelyik alapján.
4

De most így az interfészeknek

imdawe · 2011. Feb. 8. (K), 12.25
De most így az interfészeknek akkor nem sok értelme van mert ha jól veszem ki a kódból. A és B osztályok ugyanúgy tartalmazzák az info metódust. Így ezek nélkül is helytelenül le kellene futnia.

Tehát akkor az interfészek akkor csak azt szabják meg hogy milyen metódusoknak kell szerepelnie az adott osztályban? Így biztosítva valamit ami a helyes programozást segíti elő? Magyarán felület alatt azt érted hogy megadjuk a metódusokat amiket majd használni kell?

Amit pedig az absztrakt osztályokról írtál azt nem túlságosan értettem meg.
Átfogalmazom a kérdést. Egy absztrakt osztályt mikor létrehozunk a konstruktorban megadott rész lefut és az ott meghívott metódus betöltődnek/lefutnak ugye.

De ha van mondjuk más metódus amit nem használok az adott osztályban hanem azokat szeretném használni egy származtatott osztályban tegyük fel absztrakt osztály (MVC) esetében a front kontroller és alatta az egyes modulok kontrollerei a származtatott osztályok és az absztrakt osztály metódusait akarom használni a származtatott osztályokban. Így már a használata értelmet nyer, vagy sem?

Köszi a válaszokat!:)
Üdv Dénes!
5

Interface

janoszen · 2011. Feb. 8. (K), 12.32
Az Interface akkor jó, ha írsz mondjuk egy olyan osztályt, amit más valaki fog használni, esetleg több féle megvalósítás is lehet (pl. adatbázis absztrakció, cache réteg, GUI elem) de mindenhol egy egységes felületen akarod elérni. Ez különösen akkor jó, ha meg akarod adni az esélyt másnak, hogy implementáljon egy hasonló dolgot, de belül teljesen más viselkedése legyen, esetleg más osztályoktól származzon.

Az absztrakt osztály akkor jó, ha egy közös viselkedést akarsz kiemelni, vagy a fenti példával élve és mindamellett kényszert akarsz alkalmazni a gyerekosztályokra.

Magyarán szólva, ha nem feltétlenül biztos, hogy a közös viselkedés implementálása célszerű, akkor használj interfacet, ha kötelező, abstractot.
6

Egyrészt, megette a fene, ha

neogee · 2011. Feb. 8. (K), 20.47
Egyrészt, megette a fene, ha az MVC-ben egy modul vezérlő rétegét a front controllerből szármasztatod, mivel a front controllernek tudomásom szerint teljesen más feladatokat kell ellátnia. De lehet én tudom rosszul.

Másodszor:

Tegyük fel, hogy van 10 féle vezérlőd objektumod.
Tegyük fel továbbá, hogy minden vezérlő objektumnak van egy olyan viselkedése, hogy eldönti magáról, hogy az adott usernak van e joga futtatni az adott folyamatot.

Nyilván való, hogy ezt nem fogod 10szer lekódolni, és az is nyilvánvaló, hogy olyan osztálynak nem sok értelme van önmagában példányosítva, ami csak annyira képes hogy leellenőrzi hogy lefuthat e egyáltalán bármilyen metódusa.

ekkor nyúlsz az absztrakt őshöz. A fent említett viselkedést kiemeled egy abstract ősosztályba, mivel ez a művelet mindig ugyan úgy végzendő, azonos logikával.

ebből az ősosztályból származtatsz N darab vezérlőosztályt, és minden az ősből származtatott vezérlőd képes lesz eldönteni magáról, hogy a usernak van e joga hozzá, vagy sem.

Interface:
Jobban nem tudom leírni mint poetro, csak másképpen.
Egy osztály felülete (interface-e) az általa tartalmazott publikus metódusokból áll.
A felület tehát nem más, mint az a része egy osztály objektum példányának, amelyet más objektumok elérhetnek.

Az interfacek egyébként kis projektek esetén feleslegesek. De amikor egy nagyobb projektbe vág az ember, és netán többen is dolgoznak rajta, akkor érdemes megfontolni a használatukat.
13

Én úgy tudtam hogy MVC-ben

imdawe · 2011. Feb. 10. (Cs), 19.07
Én úgy tudtam hogy MVC-ben front controller feladata a kérések rootolása feldolgozása és egyéb műveletek: köztük a modulok betöltése.
Ahogy én olvastam én úgy képzeltem ezt el lépésekben hogy:
- felhasználó küldi a kérést hogy xy adatot akar meg jeleníteni
- front controller ellenőrzi hogy neki-ezt szabad-e, ha igen létrehozza az adatbázis kapcsolatot, ezután betölti a modulok vezérlőit
- a modul vezérlő elvégzi a dolgát (pl híreket lekéri)
- ezután front controller kapja vissza a főszerepet betölti a view-t, azt amit a modul szeretne.
- végül a front controller össze állítja a weblapot és elküldi a felhasználónak.
Nem így kellene működnie?:P
14

De, elviekben ez a helyes

neogee · 2011. Feb. 11. (P), 09.59
De, elviekben ez a helyes mukodes. Bar a modulnak nem feltetlenul kell megmondania mien viewba legyen betoltve a kimenete, sot szerintem meg csak ne is tudja.
Viszon ettol fuggetlenul az egyes modulok vezerloit nem az fc-bol szarmaztatod, mint ahogy nem sokkal feljebb mondtad.
15

Az már helyesebb megoldás ha

imdawe · 2011. Feb. 13. (V), 07.31
Az már helyesebb megoldás ha készítek egy külön osztályt erre ami a modul és a front controller között kommunikál. Mert ugye a modulnak szüksége van adatbázis kapcsolat és a többi és a többi. A másik meg amit nem értek hogy a modul miért ne tudjon arról hogy milyen view-nek kell majd betöltődnie? Vehetjük úgy hogy van egy $_GET['valami'] változóm és ha abban a változóban ami éppen van a hozzá tartozó view töltődik be. És ezt mégis hol máshol kéne meg szabnom ha nem a modulban?
16

Abban a vezérlő egységben ami

neogee · 2011. Feb. 13. (V), 23.54
Abban a vezérlő egységben ami a kimenet összeállítását végzi.
A modulnak azért nem kell és szerintem nem is szabad tudnia róla hogy a kimenete hol fog megjelenni, mert a modul semmi mást nem csinál, csak parancsot dolgoz fel. Nem foglalkozik vele, hogy lesz-e kimenet, és ha lesz kimenet, akkor milyen és hol.
Őt csak az érdekli, hogy a parancs amire utasítják az lefusson, vagy ha nem tud lefutni, akkor értesítse róla a vezérlőt, aki eldönti, hogy ebben az esetben mit kell tenni. Egyszerű példa:

Adott egy modul, ami azzal foglalkozik, hogy a rendszerben lévő cikkeket vadássza össze.
Tegyük fel, hogy ezek a cikkek megjelennek a weboldalon egy formázott kimeneten is, illetve megjelenik egy RSS kimeneten is.
Ilyenkor mit csinálsz?

Vegyük a te eseted, amikor a modul tudja, hogy milyen view-ban fog megjelenni.
Elkezdesz vadul if-ezni a modulban, mikor a modulnak baromira semmi köze ehhez. :) A modulnak annyi a dolga hogy kommunikál az adatbázissal, és visszaadja az összes cikket egy előre definiált struktúrában.

Amíg az én verziómban semmit nem kell tenned. Egyszerűen értesíted a modult, hogy dolga van, visszaadja az adatokat, majd a visszakapott adatokat átadod egy olyan rétegnek ami semmi mással nem foglalkozik, mint azzal, hogy a kérés paramétereiből, illetve egyéb konfigurációs beállításokból összeállítja a layoutot, és lerendereli a kimenetet. Ez a réteg fogja tudni, hogy az adott modul adott parancsának eredményézhez milyen templatet kell alkalmazni, illetve hogy hol helyezkedik majd el a layouton belül, stb stb...

Tovább folytatva a gondolatmenetet: mi van ha egy harmadik viewban is meg kell jelennie? Vagy mi van ha az egyik view-nak lecseréled a nevét? A te esetedben ezektől a dolgoktól függeni fog a modul, és ez nem jó. Több munka, nehezebb kezelhetőség.

Míg ha ezekkel a dolgokkal nem foglalkozol a modulon belül, akkor ezek után ha bármilyen alkalmazásban egy olyan modulra lesz szükség ami a hírek kezeléséért felelős, ezt a modult bátran használhatod, mert nem kell alkalmazkodnia semmilyen szinten sem az őt körülvevő rendszerhez. Megkapja a paramétereit, kinyeri az információkat és visszaadja. Hogy aztán az általa kinyert információval mi történik, az már nem az ő dolga. Ha bármilyen módosulás van a megjelenítendő templateben, vagy más templatet kell alkalmazni az adott parancshoz, akkor elég egy konfigurációs beállítást módosítanod. És egy sort nem kellett újraprogramozni, vagy kiegészíteni. :)
17

Kevered a szezont a fazonnal.

Joó Ádám · 2011. Feb. 14. (H), 00.20
Kevered a szezont a fazonnal. Modulnak általában vezérlők egy csomagját szokás nevezni, például egy fórumot. Amiről te beszélsz, az a modell, ami absztrakciós réteget képez a vezérlő és az adatforrás (relációs adatbázis, fájlrendszer, webszolgáltatás stb.) között.

Egy egyszerű MVC megvalósítás a weben többnyire úgy néz ki, hogy az alkalmazás megkapja a kérést, az alapján kiválasztja a megfelelő vezérlőt, ami módosítja és/vagy lekérdezi a modell adatait, végül összeállítja a kimenetet és visszaadja a választ. Ezt persze a végletekig lehet cifrázni, de a lényeg változatlan.
18

Értem :) Akkor lehet én

neogee · 2011. Feb. 14. (H), 00.57
Értem :)
Akkor lehet én tévedek nagyon nagyot, amikor úgy képzelem, hogy egy layout összeállításához 4-5 vagy akár még több modul együttműködése is szükséges lehet. :)
Véleményem szerint a egy modulnak semmi köze a kimenethez. Ne állítson össze semmilyen kimenetet, és ne babráljon semmit. Arra legyen egy másik egység ami viszont csak azt kezeli és semmi mást. Persze lehet, hogy ugyanarról beszélünk, csak az elnevezésekkel van gond.

Nálam így néz ki egy ilyen kérés feldolgozása:

-Felhasználó elküldi a kérést.
-FrontController megkeresi a parancshoz tartozó egységet/egységeket
-Ha a futtatott egységekből jön vissza adat, nyilván meg kell őket jeleníteni ezért megkapja a kimenet összeállítását végző egység a vezérlést
-A fent említett egység összevadássza a kéréshez tartozó templateket és lerendereli az egységeket, majd összeállítja egy egésszé (vagy éppen részenként küldi el).
-A felhasználónál megjelenik a kimenet.

Az én értelmezésemben egy modul az egy olyan egység ami egy adott témakörrel kapcsolatos feladatok ellátására "szakosodott". Ahogyan te is mondtad, pl egy fórum. Egy modul alapvetően két részből tevődik össze nálam. Minden modulnak van egy vezérlőegysége, ami a bemenetet ellenőrzi, illetve azt hogy az adott modul adott művelete egyáltalán lefuthat-e a kért paraméterekkel, illetve van egy olyan rétege ami kizárólag az adatbázi / file vagy akármilyen más műveletekért felelős, ha úgy tetszik akkor nálam egy modul controllerből és modellből áll.
Ezen kívül van az alkalmazásnak egy FrontControllere ami arról gondoskodik, hogy melyik modulok szükségesek az adott parancs értelmezéséhez. Valamint van a rendszerben egy olyan réteg, ami arról gondoskodik, hogy a felhasználó milyen kimenetet kapjon maga elé, ezt nevezhetjük nálam viewnak. Mint mondtam: összeszedi a templéteket és feltölti a modulok által visszaadott adatokkal, majd összeállítja a részkimeneteket egy egésszé, majd ezt a kimenetet visszadobja a frontcontrollernek, aki meg majd eldönti hogy mit kell vele csinálni. Elküldeni, vagy éppen kesselni, vagy mindkettő, vagy akármi mást... Nevezhetjük ezeket az egységeket akárhogyan, de szerintem ettől a megvalósítástól kellőképpen rugalmassá válik a rendszer, és nem függenek az egyes rétegek a többi rétegtől.
7

Interface

neogee · 2011. Feb. 8. (K), 21.10
Közben eszembe jutott egy jó példa az interface-ek alkalmazására.
Nemrég csináltam egy rendszert, amiben voltak bizonyos objektumok amik egy egy adatbázis tábla egy egy sorát reprezentálták.

Egy ponton célszerűvé vállt (azthiszem trace-eléshez, de már nem emlékszem pontosan), hogy ezek az objektumok legyenek bejárhatóak egy hagyományos foreach() segítségével.

Ekkor fordultam pl az interfacekhez. A phpban van egy iterator interface, amit te is implementálhatsz akármelyik osztályodban, és pont azt éred el vele, hogy foreach segítségével bejárhatóvá válik az objektum. Néha nagyon jól tud jönni... :)

Aztán egy másik példa lehet, hogy egy régebbi rendszerben az adatbázis osztályod asszociativ tömböt ad vissza a lekérdezések után, de egyszer csak eldöntitek, hogy mostantól ne tömböt, hanem objektumot adjon vissza. Ahhoz hogy ne kelljen felborítani mind a kismillió felhasználásnál a kódot, célszerű implementálni az osztályban az interface, illetve az array_access interfaceket, így a jövőben tömbként is, és objektumként is használhatóak lesznek az objektumaid. viszont nem kellett a komplett forrást átírni. :)

Így hirtelen ennyi jutott eszembe.
Remélem segít:)
8

Köszönöm a segítő

imdawe · 2011. Feb. 9. (Sze), 04.47
Köszönöm a segítő készségeteket!
Kielégítő válaszokat kaptam, így már értem hogy melyik mikor célszerű!:)
9

Iterator és array_access,

neogee · 2011. Feb. 9. (Sze), 09.18
Iterator és array_access, csak elirtam.
10

Jól van. :) Dokler akadémián

imdawe · 2011. Feb. 9. (Sze), 10.56
Jól van. :)
Dokler akadémián néztem a videókat az objektum orientáltságról és ott nem igazán értettem meg a lényegét annak amiről kérdeztem hogy miért is jó és nem találtam érthető magyarázatot sem a neten de így már minden világos még egyszer köszönöm. :)
11

Ha rétegezed az

inf · 2011. Feb. 9. (Sze), 11.11
Ha rétegezed az alkalmazásodat, akkor elég csak az interfészeket megnézni az adott rétegből, hogy lássad, hogy mit vár a réteg, és mit ad vissza. Kis dokumentálással teljesen érthetővé tehető a működés, és nem kell az osztályokat túrni azért, hogy megértsd, hogy hogyan működik a réteg. Szóval dokumentációs szempontból is elég nagy jelentősége van az interfészeknek.
12

Igy van. Tulajdon keppen ez a

neogee · 2011. Feb. 9. (Sze), 19.21
Igy van. Tulajdon keppen ez a legnagyobb elonye, illetve hogy egy szabvanyos hozzaferesi feluletet biztosi objektumok egy vagy tobb csoportjahoz, igy biztos lehetsz benne hogy a metodus amit hivsz az supportalva van, es lesz is. Es bar abban nem lehetsz teljesen biztos hogy az azonos interfacet implementalo osztalyok azonos szerkezetu adatokkal ternek vissza, azert valamilyen szinten szamithatsz ra. Egyebkent ha az intrfaceket kombinalod qz absztract osztaltokkal, ugy hogy az absztrakt osztaly implementalja az interfacet, es ebbol az osbol szarmaztatod a komponenseket, akkor eleg szoros megkoteseket lehtet kialakitani ahhoz, hogy valoban eleg legyen megnezni az interfaceket qmiket egy ososztaly implemental es ertheto is a rendszer mukodese.