Jó az, ha a leszármazott más típussal tér vissza, mint a szülő?
Okoz-e valakinek lelki sérülést egy olyan húzás, ha a szülő osztály egy metódusa más típusú értéket ad vissza, mint a leszármazotté? :-)
(szóval, hibának számít-e, ha ilyet teszek?)
Visszatértem az alapokhoz és újra 0-ról próbálom felépíteni a kis oldalamat. Itt kaptam valakitől az ötletet, hogy a rekordok kezelésére nem ártana egy absztrakt osztály, aminek a kiterjesztésével hozhatom létre a tényleges adatokhoz szükséges osztályokat.Ez így mennyire gázos?
Normális körülmények közt a fenti szülő és leszármazott működése csak annyiban tér el egymástól, hogy a gyerek osztály végrehajt egy ellenőrzést a beolvasott adatokon és exceptiont dob, ha egynél több sort talált a kulcsához. Ha nem írom felül a getData-t, akkor a visszaadott értékre mindig kétdimenziós tömbként kellene hivatkozni, ami kényelmetlen lenne.
De egyáltalán az, hogy az egyedi kulcsból létrejövő objektumokat külön kezelem, ez mint elképzelés elfogadható?
(RDBMS-t használva nincs sok értelme, hiszen ráhúzok a megfelelő mezőre egy unique key-t és nem kell tovább foglalkozni vele, de gondolok arra az esetre, ha mondjuk rámjön a hülyeség és mondjuk CSV file-t akarok "adatbázis" helyett használni)
■ (szóval, hibának számít-e, ha ilyet teszek?)
Visszatértem az alapokhoz és újra 0-ról próbálom felépíteni a kis oldalamat. Itt kaptam valakitől az ötletet, hogy a rekordok kezelésére nem ártana egy absztrakt osztály, aminek a kiterjesztésével hozhatom létre a tényleges adatokhoz szükséges osztályokat.
abstract class RecordHandler {
protected $buffer=array(); # Ide kerülnek a beolvasott adatok
# Egy tömbelem=egy sor, minden sor egy-egy tömb,
# melyben egy-egy elem=a sor egy mezője
...
public function getData(){
...
return $buffer;
}
...
}
# ez egy olyan osztály, amely biztosítja, hogy az objektum csak akkor jöjjön
# létre, ha a létrehozásához megadott kulcshoz max. 1 sor/rekord tartozik
# a tárolóban (ami nem feltétlenül RDBMS, ezért a körülményes megfogalmazás)
abstract class UniqRecordHandler extends RecordHandler {
...
public function getData(){
...
return $buffer[0];
}
}
Normális körülmények közt a fenti szülő és leszármazott működése csak annyiban tér el egymástól, hogy a gyerek osztály végrehajt egy ellenőrzést a beolvasott adatokon és exceptiont dob, ha egynél több sort talált a kulcsához. Ha nem írom felül a getData-t, akkor a visszaadott értékre mindig kétdimenziós tömbként kellene hivatkozni, ami kényelmetlen lenne.
De egyáltalán az, hogy az egyedi kulcsból létrejövő objektumokat külön kezelem, ez mint elképzelés elfogadható?
(RDBMS-t használva nincs sok értelme, hiszen ráhúzok a megfelelő mezőre egy unique key-t és nem kell tovább foglalkozni vele, de gondolok arra az esetre, ha mondjuk rámjön a hülyeség és mondjuk CSV file-t akarok "adatbázis" helyett használni)
Csinálj first és last
A lényeg mindig, hogy egyértelmű legyen a metódus nevéből, hogy mit kapsz tőle, ha úgy csinálod, hogy egyszer egy recordot, másszor meg egy tömböt ad recordokkal, akkor az nem egyértelmű, szóval szerintem gáz.
"Jó az, ha a leszármazott más típussal tér vissza, mint a szülő?"
Erre válaszolva: helyzet függő. A típus jelen esetben meg ugyanaz, mivel mindkettő tömböt ad vissza, csak az egyik két dimenziósat...
Köszi. Ami az eltérő típust
Ami az eltérő típust illeti: "fizikailag" valóban mindegy, tömb-tömb mindkettő.
De logikailag az egyik dimenzió egy rekordszerkezet, csak ezt a fogalmat a PHP nem ismeri. A szülő egy meghatározatlan típusú rekordokat tartalmazó tömböt ad vissza, míg a leszármazott azonos metódusa magát a rekordot.
Ha jól értem, akkor nem célszerű olyan metódusokat készíteni, amelyeknek nem egyértelmű a kimenete -> jobb, ha a Uniq* osztály kap egy másik metódust, ami a rekordot dobja vissza és megtartja az eredetit, ami ugyanezzel tér vissza, de egy tömb 0. elemeként. (azzal nem akarok foglalkozni, hogy egyenként visszaadogassam a beolvasott rekordokat, mert feleslegesen elbonyolítaná az életem)
Jól érted.
Az öröklődésben az a pláne,
De ez az egész architektúra nem tűnik szerencsésnek, hacsak nem tudod egyértelműen a tároló típusához kötni, hogy egyediek-e benne a rekordok vagy sem. Pl. ha van egy CSV fájlod nem egyedi kulcsokkal, a RecordHandlerből leszármaztatsz egy CsvRecordHandlert, abban megírod a CSV kezelés alacsonyszintű részleteit, aztán jön egy másik CSV egyedi kulcsokkal, akkor választhatsz, hogy a UniqueCsvRecordHandlert a CsvRecordHandlerből vagy a UniqueRecordHandlerből származtatod, és a másik kódját duplikálnod kell benne.
...
Ez folyton kimarad... (értsd: elfelejtem, pedig néhányszor már felhívták rá a figyelmem :( )
Ilyenek miatt futok neki az egésznek már sokadszor.
És nem utoljára. :(
Legutóbb pont azon akadtam el, amit te is írtál, hogy duplikálni kellene a kódot bizonyos esetekben, az viszont nem túl jó ötlet...
Ha a projekt végén nem érzed
Haha +1 :-)
És ha már az elején ezt
Több, mint fél év alatt nem jutottam el odáig, hogy legyen egy bejelentkező képernyőm. :-)))
----------------------------------------------------------
És minek nevezitek azt, aki feltalálja a kereket?
Optimistic Concurrency Control témában keresgélve jutottam el a Propel oldalára és... rá kellett jönnöm, hogy ORM-t írok. :-D
Nyugi, pár hónap / év, és
Meg érdemes lenne elolvasnod egy-két komoly könyvet a témában, hogy legyen rálátásod, hogy mi az, ami már készen van, és csak meg kell tanulnod használni...
Ehh... bocs, azt hittem,
Csak röhögni tudok magamon: előszedtem a régi, már lezárt blogom és utánaszámoltam, hogy december óta nyűglődök ezzel a hülyeséggel és nem jutok egyről a kettőre. Időkitöltésnek használom, hogy ne öljön meg az unalom, ugyanakkor nem érdekel eléggé ahhoz, hogy komolyan elmélyedjek benne.
Már nem fogom kinőni.
A kerék feltalálásával kapcsolatban azért vigasztal, hogy annyira nem indulok rossz úton amikor a maradék agysejtjeimet próbálom munkára fogni, elvégre mások már előttem kitalálták és nekik működik is. :-))
---
Ettől függetlenül, ha tudsz ajánlani szakirodalmat, azt bármikor szívesen...
Most egy PHP és MySQL webfejlesztőknek, Hogyan építsünk webáruházat c. könyv van mellettem a szekrényen, de ez inkább csak arra jó, hogy összezavarjon sokmindent.
(nem a könyv hibája, csak ők más utakon járnak, mint én)
http://www.amazon.com/Clean-C
The only valid measurement of
:-)
Köszi.
Látom a lényeget te is
De milyen igaza van! :-)
Hát jó, hogy igaza van, ez az
A 11.-re nincs ötleted addig
Valami mégsem tiszta. Mi
Mi értelme a felülírható/-definiálható metódusoknak ilyen formában?
Hiszen, ha tartom magam ahhoz, hogy a leszármazott objektumnak akkor is helyesen kell működnie, ha olyan helyen használom, ahol a szülőre van szükség, akkor gondot okozhat a felülírt metódus eltérő működése is...
Mit értelmezek rosszul?
Én nem tudom :-P Lehet, hogy
Lehet, hogy a single responsibility-t nem tartod be, például.
Az lehet a probléma, hogy nem interface-ekben gondolkodsz, hanem osztályokban. Ha interface-t vársz el, akkor az adott felületet mindkét osztálynak meg kell valósítania, szóval mindkettő működni fog az adott környezetben. Ennyi.
Van benne valami (hogy Vágó
Leginkább valami makróféleségként kezelem az osztályokat, de...
Az továbbra is zavar, hogy egy örökölt metódus felülírásának csak akkor van értelme, ha az valamit hozzátesz a szülő metódusának működéséhez. Ettől kezdve viszont semmi biztosíték nincs rá, hogy azonos inputból azonos outputot fog produkálni -> ettől kezdve viszont nem feltétlenül lehet a szülő helyére írni a leszármazottat. Na ezen még rágódnom kell egy sort.
--------
update: végiggondolva amit itt leírtam, végülis hülyeséget beszélek. Amin most "rugózok", az pont arra példa, hogy azonos szülő, azonos metódus, eltérő működés, de azonos végeredmény: Szülő absztraktként megfogalmazva, a leszármazottak eltérő adatforrásokból dolgoznak, de a visszaadott eredmény minden esetben egy-egy rekord tartalma. Illetve az update/delete műveleteknek is azonos eredménye kell, hogy legyen.
Nyilvánvaló; ha eltérő lenne
Erre reggel még volt egy jó
Valami olyasmin gondolkodtam, amit triviális példaként szoktak hozni az OOP oktatásakor:
class jármű { ... function mozgás(){ ... } }
class bicikli extends jármű { ... }
class repülőgép extends jármű { ... }
class hajó extends jármű { ... }
Mozgásra mindegyik képes, de ugye egyáltalán nem mindegy, hogy hol, hogyan, merre, milyen közegben. Ráadásul itt a jármű osztály mozgás metódusának inkább absztraktnak illene lenni, mivel azt nem lehet egyértelműen a jármű fogalmához rendelni. Igaz viszont az is, hogy visszatérési értékként nehezen tudnék kiötleni olyan adatot, ami értelmes és mégis függ attól, hogy miféle járműről van szó... Szóval már nem tudom reprodukálni.
update: jut eszembe, talán az üzemanyagszint mérő metódus lehetett és pl. gőzmozdony lett volna az egyik jármű? Mert ugye ott még a mértékegység is más lenne...
Hát ezek a példák nagyon nem
Mindegyik jármű x,y,z irányban tud mozogni.
Az üzemanyagokat meg leadott teljesítményben lehet mérni, ha mindenképpen valami közös jellemzőt akarsz keresni, de ez egyáltalán nem muszáj...
Liskov-féle helyettesítési elv
Még mindig...
Maga az alap, egy absztrakt osztály lenne, ami független az adattárolótól (mindegy neki, hogy adatbázis, soros file, XML stb.), de néhány alapművelet már definiálva van (pl. hogy adom vissza a rekord tartalmát, az update jellegű műveletek körüli ellenőrzések egy része stb.)
Ehhez kapcsolódna leszármazottként egy osztály, amely már tisztában van vele, hogy mondjuk egy MySQL adatbázissal kell kommunikálnia.
Eleve nem tudom, jó irányba megyek-e. Példaként: van egy absztrakt RecordHandler és van egy UserData extends RecordHandler. A UserData már tudja, hogy egy MySQL van mögötte, ennek megfelelő metódusokkal írja felül a RecordHandler absztrakt metódusait, amelyek a fizikai olvasást/írást definiálják.
Ha ezzel nem mentem tévútra, akkor a következő kérdés: általában jó, ha egy weblap letöltésekor csak egyszer konnektálok az adatbázishoz. Honnan vegye az említett UserData az adatbázis objektumot (szándékaim szerint egy PDO objektum)? Minden ilyen objektum próbáljon kapcsolódni önmaga? Csináljam amit eredetileg: a lap elején egy globális változóba rakom az adatbázis objektumot és az őt használó objektumok konstruktorának adjam át? Berakhatom esetleg a RecordHandler konstruktorába, hogy paraméterként elvárja az adatforrás objektumát? Egyéb? (azt nem tartom jó ötletnek, hogy az említett globális változóra közvetlenül hivatkozzak)
-----
Alapvető ismerethiányban szenvedek, de nem találok a neten olyan irományt, ami segítene :-(
(forráskódok egy része túl bonyolult ahhoz képest, amit én akarok, a maradék meg lényegesen egyszerűbb... de még nem adtam fel teljesen)
update: de az is lehet, hogy tényleg nem kéne ilyen komoly agymunkával erőlködnöm. Most találtam pár magyar nyelvű lapot, ami az OOP alapjairól szól (köztük weblaborost is), de a fenti kérdésekre továbbra sem találok egyértelmű válaszokat.
A két szokásos megoldás erre
Köszi szépen. Singleton
Singleton ügyben folyton összekavarodok: ez valójában egy olyan osztály, aminek csak egyetlen objektuma lehet és erről gondoskodik is, pl. azzal, hogy egy statikus változóban tárolja önmaga egyetlen példányát, amit egy statikus metódusból ad vissza, miközben a konstruktora privát?
Magyarán az általad említett globális változó valójában az osztály statikus változója.
Pontosan.
Másrészt a teszteléscentrikus metodológiákban nem szeretik, mert a statikus hivatkozás miatt nehéz elválasztani a hívó osztálytól.