ugrás a tartalomhoz

procedurálisból OOP

Szita Szilárd · 2013. Okt. 16. (Sze), 13.29
Hogy tudunk átalakítani procedurálisból oop-re?

  <form>
                    <ul>
                        <li>
                            <input type="text" placeholder="Felhasználónév" />
                        </li>
                        <li>
                            <input type="password" placeholder="Jelszó" />
                        </li>
                        <li>
                            <input type="submit" value="Belépés" class="button" />
                        </li>
                    </ul>
                </form>

<?php
session_start();

$host="localhost"; // Host név
$username=""; // Mysql felhasználónév
$password=""; // Mysql jelszó 
$db_name="test"; // adazbázis név
$tbl_name="members"; // tábla név 

// Csatlakozás az adatbázishoz
mysql_connect("$host", "$username", "$password")or die("cannot connect"); 
mysql_select_db("$db_name")or die("cannot select DB");

// Felhasználó és jelszó tárolás változókban
$myusername=$_POST['myusername']; 
$mypassword=$_POST['mypassword']; 

// Injection szürés
$myusername = stripslashes($myusername);
$mypassword = stripslashes($mypassword);
$myusername = mysql_real_escape_string($myusername);
$mypassword = mysql_real_escape_string($mypassword);
$sql="SELECT * FROM $tbl_name WHERE username='$myusername' and password='$mypassword'";
$result=mysql_query($sql);

// Visszakérjük a sorok számát
$count=mysql_num_rows($result);

// Ha egyeznek az adatok belép és mentjük az adatokat sessionban
if($count==1){
    session_register("myusername");
    session_register("mypassword"); 
    header("location:valami.php")
}
else {
    echo "Hibás jelszó vagy felhasználónév.";
}
?>
Na ki hogy alakítaná az alábbi kódot oopre?
Kódot nem teszteltem csak gyorsan valamit írtam :)
 
1

Procedurális?

Poetro · 2013. Okt. 16. (Sze), 13.38
Mi lenne ha előbb procedurálisra írnád át. Abban ugye függvények vannak, amit egymást hívogatják, de ebben egy darab függvényt se látok, csak egymás után bedobált sorokat (imperatív programozás).
2

De ő legalább escapel.

hunkris · 2013. Okt. 16. (Sze), 15.26
De ő legalább escapel.
3

Kezdjük itt:

Pepita · 2013. Okt. 16. (Sze), 22.58
Sorry, de valószínűleg új commentbe vadiúj kódokat fogsz írni.

Semmi baj, hogy elsőre mégsem procedurális, hívhatnánk szekvenciális utasítássornak is, de nem gond, akkor első lépések:

- Nevezd nevén a fájlokat, feltételezzük, hogy van egy document-root könyvtárad, abban pedig egy private is. Majd ide tesszük, amit nem akarunk, hogy közvetlen URL-ből elérjenek (.htaccess-el most nem törődünk, feltételezzük, hogy van és műxik).
- A root-ba csak olyan fájlokat teszünk, amik publikusak, tehát működniük kell domained/fájlnév hívásra.
- Eszerint készítsd el a honlap vázát.
- Legyen egy index.php (rootban), egy private/form.htm, private/success.htm, login.php, private/config.php.
- Próbáld meg kitalálni, hogy ennyi fájlban melyik mire való. Elsőként ezekre válaszolj (próbáld meg, minden fájlra), addig ne írj kódot.

Az index.php valahogy így néz ki, de még lehet, hogy módosítani fogjuk:
<?php  
session_start();
?>
<html>
<head>
</head>
<body>
<?php
if (isset($_SESSION['u_id'])) {
    include('private/success.htm');
} else {
    include('private/form.htm');
}
session_write_close();
?>
</body>
Ez alapján már lehet némi ötleted, hogy hogyan is fogjuk csinálni, elsőre talán nem is eljárásokkal (procedurálisan), csak imperatív módon (from Poetro), de logikusan építkezve, nem egy fájlba szórva mindent, aztán fejünket vakargatva...

Csak írd le magyarul, hogy szerinted a további fájlokban mi lesz (szépen felsorolva), és ha esetleg kihagytam valamit (simán lehet!), akkor azt is, hogy mit.

Szép lassan menjünk, lépésenként, ha már tanulunk. Egyébként nagyon profik vagyunk, mert előbb tervezünk, csak aztán kódolunk.
4

rendben

Szita Szilárd · 2013. Okt. 17. (Cs), 03.50
Rendben,ma suli utan...
5

Egyelőre csináld meg

inf · 2013. Okt. 17. (Cs), 11.20
Egyelőre csináld meg működőképesre, utána lehet elkezdeni gondolkodni azon, hogy hogyan lehet ebből oop... Szórd fel github-ra, aztán esetleg tudunk küldeni pull request-eket.
6

+1

janoszen · 2013. Okt. 17. (Cs), 18.05
+1, GitHubon en is szivesebben dolgozom.
7

Kaptam egy Macbookot fatertól :D

Szita Szilárd · 2013. Okt. 17. (Cs), 18.06
Most egy picit tanulmányozom a cuccot és majd ott nekiállok :P
8

Ez brutál

Szita Szilárd · 2013. Okt. 17. (Cs), 18.47
Nagyon gyors a gep az elozohoz kepest brutal a teljesitmenye :D :D
Na de kezdodjon a php
9

És most hol tartunk?

Pepita · 2013. Okt. 17. (Cs), 21.27
Szerintem itt kéne levezetni, mert akkor másoknak lehet linkelgetni.
Itt a GitHub-ra én -1-elek.
Kicsike kódok lesznek, simán elfér itt, és maradjunk a lépéseknél, ha már leírtam. Ne kezeljük rögtön úgy, hogy "szórj össze valamit, majd optimalizáljuk".
Ő most megérteni szeretné és megtanulni, arra rossz módszer az (és sok másra is), hogy csinálj gyorsan valamit rosszul, aztán majd javítgatjuk.
Igen javaslom, hogy maradjunk itt, és az általam írt sorrenben-sebességgel. Ha többen többfelé rángatjuk, csak káosz lesz belőle, akkor én inkább kimaradok. Nem értem, mi rossz van abban, amit indítványoztam. Pont az a lényeg, hogy lépésről-lépésre tanuljon, ne ide-oda kapkodva.
Ez nem egy határidős projekt, ne keverjük össze!
10

Egy gist olvashatóbb is, meg

tgr · 2013. Okt. 17. (Cs), 22.51
Egy gist olvashatóbb is, meg szervezettebben is lehet rajta többféle változatról beszélni (meg Markdown van BBorzalom helyett).

Ami nagyobb probléma, hogy az OOP a nagyobb komplexitás kezelésére lett kifejlesztve. Ha annyi egy feladat, hogy ellenőrizzük le, hogy egy form mező értéke szerepel egy adatbázisban, arra a fenti még-csak-nem-is-procedurális kód nagyjából adekvát megoldás. Neház úgy megérteni valamit, ha olyan példákon mutatják be, amiken semmi haszna nincsen.
11

+1, -1

Pepita · 2013. Okt. 17. (Cs), 23.56
meg Markdown van BBorzalom helyett).
Ez nagyon tetszik, még nem hallottam, megjegyzem! :)
Neház úgy megérteni valamit, ha olyan példákon mutatják be, amiken semmi haszna nincsen.
Akkor csak várd ki a végét, szerintem jó ötletem volt, de még bennem sem kristályosodott ki teljesen. Itt a fő haszon a megértés. Ehhez pedig a HelloWorld a legjobb.
Lépésenként gondolok menni procedurálisba, onnét OO. Akkor fogja megérteni szerintem, legalábbis a nagyon alapokat. Interface-t nem is tervezek, max. egy öröklődés a végére (mondjuk akkor kellhet), de csak kis lépésekben akarom bonyolítani, a mélyvíz erre tuti nem jó. Aztán szóltok, ha valamit elrontok...

Tőlem mehet akárhova, én leírtam, miért (kikért) hagynám itt. Itt akárhány tanulónak szólhat, ott kb. egynek (utólag nemigazán értik a később jövők, általában nem profi Git-felhasználók, egyébként én sem, úgyhogy ha oda megy, továbbképzés kell :)). Azért nem mindegy, ha sok időt töltök vele.
12

Az ilyen példák általában úgy

tgr · 2013. Okt. 18. (P), 01.59
Az ilyen példák általában úgy végzik, mint a SimplePHPEasyPlus, ami elég korrektül bemutatja, hogyan kell objektumorientáltan programozni, de egyáltalán nem derül ki belőle, hogy miért kell. (Merthogy egy bizonyos komplexitás alatt valóban nem kell.) Nyilván meg lehet csinálni a hello worldot moduláris HMVC service container alapokon is, de aki előtte nem értette, hogy mire jó a modularitás, a HMVC vagy a service container, az nem ebből fogja megérteni.
13

"Bizonyos komplexitás"

pkadam · 2013. Okt. 18. (P), 22.21
És mi ez a bizonyos komplexitás? Tudjuk valahogy definiálni, hogy pl. ˆ„ha csak a és b funkcióra van szükséged, akkor a legjobban a procedurális úttal jársz, c esetén már megfontolandó az OOP, ha viszont már d és e funkciók szükségesek, csak objektumorientáltan érdemes”?

Nekem egyfajta dogmatikus paradigmaváltásnak tűnik az OOP, és nem láttam még úgy megközelítve, hogy „ez a kód így procedurálisan jó, de a felhasználókat célszerűbb lenne objektumként kezelni”. Inkább az érződik, hogy „na, innentől akkor minden objektum”. Nem értem, hogy ha szeretnék például kiíratni egy műveletről értesítést a felhasználónak, akkor egy result(0,'Hiba!') ill. result(1,'Siker!') jellegű függvények helyett miért kellene

$result = new Result();
$result->setType(0);
$result->setText('Hiba!');
$result->render();

módon elérnem ezt. Még akkor sem, ha tudom, hogy (new Result(0,'Hiba'))->render() módszerrel is megoldható a PHP 5.4 óta. Vagy ha a render() metódus benne van a konstruktorban, és esetleg lenne egy Error osztályom, ami a Resultból öröklődik, akkor se a típus megadása, se a renderelés explicit meghívása nem kell, csak egy new Error('Hiba'). És persze ezt a fajta öröklődést eljátszhatom procedurálisan is, ha az error($msg) meghívja a result($type,$msg) függvényt a szükséges első paraméterrel.

Őszintén örülök, hogy elindul egy ilyen kezdeményezés az OOP-re való áttérés gyakorlati bemutatásáért – szerintem van miről beszélni.
14

És mi ez a bizonyos

inf · 2013. Okt. 19. (Szo), 01.28
És mi ez a bizonyos komplexitás? Tudjuk valahogy definiálni, hogy pl. ˆ„ha csak a és b funkcióra van szükséged, akkor a legjobban a procedurális úttal jársz, c esetén már megfontolandó az OOP, ha viszont már d és e funkciók szükségesek, csak objektumorientáltan érdemes”?


Ha elvont a problémád: magas absztrakciós szintű, akkor elég egyértelmű, hogy magas absztrakciós szintű eszközöket érdemes használnod: objektum orientált megközelítést. Ha nagyon konkrét a problémád: alacsony absztrakciós szintű, akkor el kell gondolkodni azon, hogy tényleg annyira konkrét e, és ha igen, akkor érdemes alacsony absztrakciós szintű eszközöket használnod: procedurális megközelítést.

Ha rugalmas, cserélhető, könnyen karbantartható kód kell, akkor olyat oo-ban könnyebben lehet írni, mint procedurálisan, mert vannak direkt ilyen célra kitalált eszközök. Ha procedurálisan akarsz könnyen karbantartható kódot készíteni, akkor arra is lehetőséged van, csak ezeket az eszközöket újra fel kell találnod hozzá, ami meg úgy általában időpazarlás, mert már más megcsinálta helyetted sokkal jobban. Szerintem az esetek 99.9%-ában érdemes oo nekikezdeni a problémának. A maradék 0.1% az, aki alacsony szintű dolgokat ír, vér profi, és pontosan tudja, hogy mit csinál. Bármennyire is szeretnéd, nem tartozol ebbe a kategóriába, különben nem ezt a fórumot olvasnád... :-)
15

Az alábbi kódok tartalom

inf · 2013. Okt. 19. (Szo), 01.57
Az alábbi kódok tartalom szempontjából teljesen azonosak, mindegyikben szerepel, hogy mit csinál az adott kód.

A.)
result(0,'Hiba!') // rendering result(type, text)


B.)
renderResult(array(
'type' => 0,
'text' => 'Hiba!'
));


C.)
$result= array();
setType($result, 0);
setText($result, 'Hiba!');
render($result);


D.)
$result = new Result();
$result->setType(0);
$result->setText('Hiba!');
$result->render();


E.) - fiktív tgr kedvéért (utólag hozzászerkesztve)
renderResult(
    $type = 0,
    $text = 'Hiba!'
);


Szerinted melyik a legkönnyebben olvasható, módosítható, karbantartható?
16

Ennek mondjuk nincs köze az

tgr · 2013. Okt. 19. (Szo), 02.06
Ennek mondjuk nincs köze az OO-hoz, a PHP-ben nem képesek implementálni a nevesített paramétereket, amikkel jobb nyelvek megoldják ezt a problémát.
17

A kód olvashatósága akkor is

inf · 2013. Okt. 19. (Szo), 02.21
(bocs, közben szerkesztettem az előzőt, nem gondoltam, hogy hozzászólnak)

A kód olvashatósága akkor is rosszabb lesz, maximum ha eltördelik paraméterek szerint külön sorba, meg a result-nak külön névteret adnak, akkor talán kevésbé.

Imho mindent meg lehet csinálni procedurálisan is amit oo-ban, csak jóval körülményesebb, legalábbis eddig ahányszor próbáltam, nem tudtam olyan példát felhozni, ami oo-ban ment, és procedurálisan nem...

Tényleg csak az eszközök kidolgozottságában van különbség. Szerintem az osztály egy absztrakció, amit ismétlődő procedurális kódminták alapján találtak ki. Kb olyan, mint oo-ban a programtervezési minták. Nyilván valamelyest szűkíti az elérhető lehetőségek körét, de mint best practice cserébe elég sokat ad. Ugyanez a helyzet a tervezési mintákkal is és a solid elvekkel is. Ha már itt tartunk, akkor ugyanez a helyzet a nevesített paraméterekkel is... :-)

Szerintem az oo használata mellett a fő szempont a kód olvashatósága, karbantarthatósága, a közös nevezéktan egyes mintákra, amit osztály nevekben is jelölni lehet, plusz néhány mankó, ami az osztályok sajátsága: adatrejtés, polimorfizmus, interface-ek, stb... Szóval egyértelműen az oo-val kapcsolatos beépített eszközök, amiben többet nyújt a procedurálisnál, minden más pedig a programozón múlik. Ha nem használja ezeket a beépített eszközöket, vagy nem megfelelően használja, akkor simán lehet rosszabb minőségű a kódja, mint egy procedurálisan írt kód. Szóval az oo megközelítés egy eszköztár, ami szakértelmet igényel, cserébe - megfelelően használva - megkönnyíti a munkát, ugyanúgy mint minden eszköz.
18

+1

Pepita · 2013. Okt. 19. (Szo), 05.58
Szerintem az oo használata mellett a fő szempont a kód olvashatósága, karbantarthatósága
Már ezért megéri, és nem kell a szükségszerűséget vizsgálni a megértéshez.
minden más pedig a programozón múlik
Így van, miután legalább nagyjából érti, miről van szó.
simán lehet rosszabb minőségű a kódja, mint egy procedurálisan írt kód
Ez is pontosan így igaz. Ezért ajánlom továbbra is a pofonegyszerű megközelítést, kis lépésekben.

Igen, egy szerszámkészlet, a tervezett csobogódat is összehozod egy csavarhúzóval, egy kombifogóval és némi cikkcalaggal, vagy felszereled magad rendesen: blankolófogó, saruzófogó, érhüvelyező, forrasztópáka, .......
Remélem neked többet is elmond a példám. :)

Szerk.: én továbbra is várom a kérdező megnyilvánulását: most megyünk arra, amerre javasoltam, vagy nem? Vitatkozni nem akarok többet róla, mindenki másképp látja a világot. Azért is találtam ezt ki, mert hátha még valaki meglátja benne a "tetszetős" momentumokat (nem mondom meg ki, de konkrét személyre gondolok).
20

Szerintem az oo használata

Hidvégi Gábor · 2013. Okt. 19. (Szo), 09.05
Szerintem az oo használata mellett a fő szempont a kód olvashatósága, karbantarthatósága, a közös nevezéktan egyes mintákra, amit osztály nevekben is jelölni lehet, plusz néhány mankó, ami az osztályok sajátsága: adatrejtés, polimorfizmus, interface-ek, stb.
Eddig még senki sem tudta bebizonyítani, hogy az OO-tól olvashatóbb, karbantarthatóbb lenne a kód, mint procedurálisan, a közös nevezéktan ez utóbbiban is használható, mint ahogy az adatrejtés is (ha van értelme és van rá szükség), a polimorfizmus pedig hatékonyan csak nagyon ritkán használható.
21

Mi szükség van erre?

BlaZe · 2013. Okt. 19. (Szo), 10.29
Miért kell ezt a témát minden héten elővenni, és tényekkel szembemenő állításokal borzolni a kedélyeket? Az OO kód karbantarthatóság és olvashatóság előnyeiről évtizedes tapasztalata van a szakmának. Komoly szakirodalma is van, érdemes elolvasni. És a poliformizmus sem csak nagyon ritkán használható - ez már megbocsáss - de butaság.

Ha kétségeid vannak, nyiss neki egy témát, hozz egy gyakorlati példát (de lehetőleg ne olyat, mint múlt héten, amiről messziről látszott, hogy mit akarsz belőle kihozni), és megbeszéljük. De ezek a tényeket nélkülöző, levegőbe puffogtatott demagóg állítások egy olyan topicban, ahol valaki az OOP tanulásában kér segítséget, nem épp szerencsések, sőt.
22

Fordítsuk meg: miért kell

Hidvégi Gábor · 2013. Okt. 19. (Szo), 11.15
Fordítsuk meg: miért kell mindig állítani valamit (OO karbantarthatóság, olvashatóság), amit már rengetegen megcáfoltak? Most akkor kinek van igaza?

A téma nyitója azért kér ebben segítséget, mert múltkor meg lett neki mondva, hogy OOP-t kell tanulnia. Neki fogalma sincs arról, hogy valójában erre van-e szüksége, valamint itt már tgr is megkérdőjelezte, hogy a felhozott példában van-e értelme bármit is objektumokkal machinálni.

Igazad van, ideje most már összeszedni egy helyen a tényeket, és be kéne mutatni az alternatívákat, mert vannak más utak is.
23

Fordítsuk meg: miért kell

BlaZe · 2013. Okt. 19. (Szo), 12.04
Fordítsuk meg: miért kell mindig állítani valamit (OO karbantarthatóság, olvashatóság), amit már rengetegen megcáfoltak? Most akkor kinek van igaza?

Megcáfolni nem cáfolták. Vannak kritikusai, mint mindennek, és legtöbben az overengineeringet hozzák fel ellenpéldának, nem a paradigma értelmetlenségét.

A téma nyitója azért kér ebben segítséget, mert múltkor meg lett neki mondva, hogy OOP-t kell tanulnia. Neki fogalma sincs arról, hogy valójában erre van-e szüksége,

Ha valaki programozóként akar dolgozni jelenleg, akkor az OOP-t meg KELL tanulni, ugyanis egy szint fölött minden normális helyen elvárás a gyakorlati alkalmazási tapasztalat. Én legalábbis eddigi pályám során még sehol nem találkoztam vele, ahol ez ne így lenne.

valamint itt már tgr is megkérdőjelezte, hogy a felhozott példában van-e értelme bármit is objektumokkal machinálni.

Azt kérdőjelezte meg, hogy miért ilyen példával kell bemutatni az OOP-t... És ebben egyet is értek vele. Nem értem ez mit cáfol. Nyilván verébre nem lövünk ágyúval, mert értelmetlen, és ki se derül belőle, hogy az ágyú mire jó.

Igazad van, ideje most már összeszedni egy helyen a tényeket, és be kéne mutatni az alternatívákat, mert vannak más utak is.

Nyilvánvalóan vannak alternatívák. A kérdés az, hogy melyik feladatra mi a jobb, hogy egy minimálisnál nagyobb komplexitású és több éves fejlesztési és karbantartási periódusú project során melyik paradigmával lehet hatékonyabban dolgozni (olvashatóság, karbantarthatóság stb). Én abban kételkedek, hogy egy tényfelsorolással ezt, vagy azt alá lehet támasztani, de a kedvedet nem akarom elvenni tőle. Ahogy tgr hivatkozott hozzászólása is rámutat, ezt értelmes gyakorlati példákon, tapasztalattal lehet felmérni és megérteni.
25

miért kell mindig állítani

inf · 2013. Okt. 19. (Szo), 15.09
miért kell mindig állítani valamit (OO karbantarthatóság, olvashatóság), amit már rengetegen megcáfoltak?


Ilyennel még nem találkoztam, mutass egy ilyen cáfolatot!
27

Az olvashatóság teljesen

Hidvégi Gábor · 2013. Okt. 19. (Szo), 16.05
Az olvashatóság teljesen szubjektív dolog, és nem hiányzik semmilyen eszköz a procedurális programozásból, amivel kevésbé olvasható kódot lehet készíteni. Ugyanígy, az OOP-ben sincs olyan eszköz, amitől olvashatóbb kódot lehet gyártani, mint procedurálisan. Has programming lost its way? Part Two. Ugyanez igaz a karbantarthatóságra is: Productivity Analysis of Object-Oriented Software Developed in a Commercial Environment.
30

Az olvashatóság egyáltalán

inf · 2013. Okt. 19. (Szo), 20.44
Az olvashatóság egyáltalán nem szubjektív dolog, nézz meg egy obfuszkált meg egy nem obfuszkált kódot. A cikkeket átnézem, majd írok később.
36

nézz meg egy obfuszkált meg

Poetro · 2013. Okt. 20. (V), 09.31
nézz meg egy obfuszkált meg egy nem obfuszkált kódot

És ebből mi fog kiderülni?
37

Hogy az obfuszkált

inf · 2013. Okt. 20. (V), 11.53
Hogy az obfuszkált mindenkinél kevésbé olvasható, mint a nem obfuszkált, tehát az olvashatóság nem szubjektív dolog...
38

Egy futtatókörnyezetnek

Hidvégi Gábor · 2013. Okt. 20. (V), 12.21
Egy futtatókörnyezetnek teljesen mindegy, hogy obfuszkált vagy szép kódot kap, neked nem, tehát szubjektív.
40

A futtatókörnyezetet

inf · 2013. Okt. 20. (V), 12.42
A futtatókörnyezetet tudtommal nem szokás emberszámba venni. Az olvashatóság emberekre vonatkozik, és nem gépekre... Minimális szubjektív része van a dolognak, minden ember kicsit más, de megfelelő mintaszámmal az ilyen kis eltérések kiolthatóak, szóval szerintem mérhető egy kód olvashatósága objektíven is.
44

Mérhető?

Hidvégi Gábor · 2013. Okt. 20. (V), 15.34
Milyen szempontok alapján?
46

Odaállítasz ezer embert két

inf · 2013. Okt. 20. (V), 15.52
Odaállítasz ezer embert két kód fölé, hogy mondják meg melyik az olvashatóbb. Az ezer ember válaszának az átlaga elég jól fogja mutatni, hogy melyik. Szóval kód összehasonlítás alapján. Sok cikket lehet találni a témában, hogy hogyan lehet olvasható kódot írni. A clean code című könyvnek foglalkozik egy külön fejezete ezzel.
43

Szubjektum

Hidvégi Gábor · 2013. Okt. 20. (V), 15.34
Minden ember kicsit más, ráadásul minden ember más szinten ismeri az adott nyelvet és mások a szokásai. Egy kezdőnek gondot okozhat akár egy $valtozo = boolean ? 'igaz' : 'nem igaz'; sor is, és egy középhaladónak sem fog feltétlenül elsőre egyértelmű lenni a DIC-ek használata. Ugyancsak nem mindenkinek segíti az olvashatóságot, ha apró függvényekre bontod a kódot (akár több fájlban), más pedig a hosszú metódusokat nem tudja átlátni. A változók és függvények, táblák és mezők elnevezése is valakinek így jó (pl. $objlat), míg másoknak amúgy (pl. $objektum_lathatosaga vagy $object_visibility).
41

Az olvashatóság nem a

bamegakapa · 2013. Okt. 20. (V), 12.42
Az olvashatóság nem a futtatókörnyezetről szól, hanem az emberi elme működéséről. Az obfuszkált kód az emberek számára nehezebben olvasható, mint a nem obfuszkált, tehát nem szubjektív a dolog.

Más szinteken már szubjektívvé válhat, egy zseni olyan kódot is könnyen olvas, amit én egyáltalán nem.
32

Az első cikk valakinek a

inf · 2013. Okt. 19. (Szo), 21.17
Az első cikk valakinek a nyavalygása, hogy olyan oop kódokat látott, amiket nem értett, hogy mit csinálnak, ezért bizonyára az oop rossz, és nem a fejlesztők, akik ilyen kódokat írnak. Lehet hasonlóan olvasható kódot írni procedurálisan, ha megvannak hozzá a megfelelő eszközök: névterek, nevesített paraméterek. Ha nincsenek, akkor nem lehet. Az egyedüli eszköz, aminek nincs procedurális megfelelője az a throw és a try-catch. Ezek talán goto-val vagy ilyesmikkel kiválthatóak, de goto sincs minden nyelvben... Szóval szerintem hibakezelés terén mindenképp fejletlenebb egy procedurális kód. De persze létezhet olyan nyelv, ami ezt is orvosolja, pl kapásból a Pl/PgSQL-ben is van valami hasonló. Összességében az, hogy az oo ad valami pluszt olvashatóságban, az erősen függ a programnyelvtől. A PHP esetében ad, mert annál nincsenek nevesített paraméterek.

A második cikk arról szól, hogy nem növeli a produktivitást az oop. A karbantarthatóságról szó sincs benne, a LOC-ot használ a produktivitás mérésére, és az elején leírják, hogy a LOC a karbantarthatóságot nem veszi figyelembe. A karbantarthatóság erősen függ a kód olvashatóságától, ami meg, mint már fentebb írtam erősen nyelv függő, hogy oo-ban lehet e jobban olvasható kódot írni, vagy csak pont ugyanannyira olvashatót, mint procedurálisan.

Összefoglalva az oo-val olvashatóbb, vagy pont annyira olvasható kódot lehet írni, mint procedurálisan, és mindez programnyelv függő. Abban az esetben, ha olvashatóbb a kód, akkor könnyebben karbantartható.
34

Hibakezelés A kivételkezelés

Hidvégi Gábor · 2013. Okt. 20. (V), 07.58
Hibakezelés

A kivételkezelés nem egy olyan nagyon különleges dolog, amit ne lehetne procedurálisan megcsinálni: egy speciális objektumot ad vissza, aminek van pár beépített változója és metódusa.

function metodus() {
  ...
  throw new SomeException();
}
try {
  $eredmeny = this->metodus();
}
cache (SomeException $e) {
  print $e->getMessage();
}
catche (Exception $e) {
  throw $e;
}
$this->kovetkezo_metodus($eredmeny);

Ezt a működést a következőképp lehet utánozni:
function fuggveny() {
  ...
  return array(
    'hibakod' => SOMEHIBA
  );
}
$eredmeny = fuggveny();
if ($eredmeny['hibakod']) {
  if ($eredmeny['hibakod'] === SOMEHIBA) {
    print hibakezelo($eredmeny);
  }
  else {
    return $eredmeny;
  }
}
kovetkezo_fuggveny($eredmeny['ertek']);


Tehát a függvényünk nem közvetlenül egy eredményt ad vissza, hanem egy indexelt tömböt, amiben szerepel a hibakód, az esetleges behelyettesítendő paraméterek, ezek akkor, ha hiba történt, különben pedig hibakódként egy 0, valamint az eredmény.

A két kód ekvivalens, mert bizonyos esetben maga az aktuális függvény kiprinteli a hibaüzenetet, ha más típusú, általános hiba történt, akkor pedig továbbadja a szülőjének, ahol lekezelhetjük ezt.

Olvashatóság, karbantarthatóság

Az olvashatóságot továbbra is szubjektívnek tartom. Az első cikkben pont arra próbáltam rámutatni, hogy csupán az OOP-től nem lesz olvashatóbb a kód, ott is csak azon múlik, aki írta. Az olvashatóságnál valóban az a fontos, amire BlaZe utal, hogy más számára is az legyen, ezt pedig bármilyen programozási paradigma mellett el lehet érni, ha van egy szabályrendszer, amit mindenki betart.
39

HibakezelésA kivételkezelés

inf · 2013. Okt. 20. (V), 12.37
Hibakezelés

A kivételkezelés nem egy olyan nagyon különleges dolog, amit ne lehetne procedurálisan megcsinálni: egy speciális objektumot ad vissza, aminek van pár beépített változója és metódusa.


Hát ez a lehető legrosszabb módja a try-catch utánzásának, ugyanis az több szint mélységből jövő hibákat is elfog. A te módszerednél minden egyes szintnél ugyanazok az if-else ágak ismétlődnének, és egy magasabb szinten mindent elborítana a hibakezelés miatti zaj. A PHP-ben van hasonló nyelvi elem hibakezelésre, azt kell használni:

function errorHandler($errno, $hibakod, $errfile, $errline)
{
    if ($errno != E_USER_ERROR)
		return false;
		
	hibakezelo($hibakod);
	return true;
}
set_error_handler('errorHandler');

function fuggveny() {
  ...
  trigger_error(SOMEHIBA, E_USER_ERROR);
}
$eredmeny = fuggveny();
kovetkezo_fuggveny($eredmeny['ertek']);
A php hibakezelővel csak a legmagasabb szinten lehet elkapni a hibákat, alsóbb szinteken nem. A try-catch blokkoknál bármennyi egymásba ágyazható, szóval több helyen el lehet kapni a hibákat, és tetszés szerint kezelni őket. Szóval a php esetében esélytelen utánozni a try-catch blokkot procedurális megoldással.

Bizonyos nyelveknél van hasonló procedurális nyelvi elem, mint a try-catch:

Pl/PgSQL

    INSERT INTO mytab(firstname, lastname) VALUES('Tom', 'Jones');
    BEGIN
        UPDATE mytab SET firstname = 'Joe' WHERE lastname = 'Jones';
        x := x + 1;
        y := x / 0;
    EXCEPTION
        WHEN division_by_zero THEN
            RAISE NOTICE 'caught division_by_zero';
            RETURN x;
    END;
A legtöbb esetben azonban ez hiányzik. Szóval ismét csak nyelv függő az, hogy az oop nyelvi eszközök adnak e valamilyen pluszt vagy sem.

Az olvashatóságnál valóban az a fontos, amire BlaZe utal, hogy más számára is az legyen, ezt pedig bármilyen programozási paradigma mellett el lehet érni, ha van egy szabályrendszer, amit mindenki betart.


Ez így van, procedurálisan is lehet olvasható kódot írni, itt is nyelvi eszközök kérdése az egész, ha szét lehet szedni a függvényeket névterekbe, és van hasonló nyelvi elem, mint a use a php-ban, amivel nem kell állandóan kiírni, hogy melyik függvény melyik névtérből van, akkor lehet ugyanolyan olvasható kódot írni procedurálisan is, mint oo-val. Ellenkező esetben nem. Gyanítom, hogy kevés az olyan nyelv, ahol ez támogatott.


Ha az adott nyelvet direkt felkészítették arra, hogy procedurálisan is el lehessen érni ugyanazokat az eszközöket, mint amiket objektum-orientáltan általában lehet, akkor procedurálisan is lehet olyan minőségű kódot írni, mint objektum-orientáltan. Ha viszont nem készítették fel erre, akkor objektum-orientáltan jobb kód minőség érhető el, bármennyire is erőlködik az ember procedurálisan. A PHP esetében a procedurális programozás kevésbé támogatott, mint az objektum orientált, így annak az esetében jobb választás objektum-orientáltan programozni. A javascript-re, java-ra ugyanez igaz. A Pl/PgSQL-re viszont ugyanez már nem igaz. Lehetne csinálni egy táblázatot az egyes nyelvekről ezzel kapcsolatban...
42

Hát ez a lehető legrosszabb

Hidvégi Gábor · 2013. Okt. 20. (V), 14.08
Hát ez a lehető legrosszabb módja a try-catch utánzásának, ugyanis az több szint mélységből jövő hibákat is elfog. A te módszerednél minden egyes szintnél ugyanazok az if-else ágak ismétlődnének, és egy magasabb szinten mindent elborítana a hibakezelés miatti zaj.
Nem, ez attól függ, hogy mit ad vissza az adott függvény, és hogy mi a programozó célja. Try - cache-nél is ugyanígy el tudod dönteni, hogy a különböző típusú kivételeket a programnak mely részén kezeled le.
47

Szerintem jóval egyszerűbb

inf · 2013. Okt. 20. (V), 15.56
Szerintem jóval egyszerűbb egy vagy két részén a teljes alkalmazásnak lekezelni az összes hibát, mint minden egyes függvényben külön foglalkozni a hibakezeléssel. Nem utolsó sorban tömörebb kód lesz az eredménye a dolognak, ami ugye jobban olvasható... ;-)
53

Valóban egyszerűbb, de a

Joó Ádám · 2013. Okt. 21. (H), 04.06
Valóban egyszerűbb, de a legegyszerűbb nem is kezelni őket. Ez nem érv. Ha egy függvény nem tudja a hívója által várt eredményt produkálni, akkor a hívója tudja eldönteni, hogyan tovább. A hibák egy igen kis része az, amikor nem tehető más, mint megállítani a program futását. Persze lehet használni kényelmes flow-controlra a kivételeket, csak akkor barátkozzunk meg a gondolattal, hogy semmivel nem különb eljárás, mint a goto. Nem véletlen, hogy Ken Thompson és Rob Pike tudatosan hagyták ki a kivételkezelést a Goból.

The primary duty of an exception handler is to get the error out of the lap of the programmer and into the surprised face of the user.


– Verity Stob
57

Jelenleg ez az egyetlen

inf · 2013. Okt. 21. (H), 14.00
Jelenleg ez az egyetlen használható megközelítés a kényelmes hibakezelésre. Ha tudsz jobbat mutatni, akkor szívesen áttérek rá... A wildcard visszatérő értékek biztosan nem tartoznak a "jobb" kategóriába.
59

Mivel a szabványos könyvtárak

Joó Ádám · 2013. Okt. 21. (H), 14.12
Mivel a szabványos könyvtárak tele vannak kivételekkel, és nem egyszer olyanokkal, amik semmi információt nem nyújtanak (IOException), úgysem tudsz áttérni. Én is együttélek velük, csak ne higgyük azt, hogy ez a jó megközelítés.
62

Jó, de tegyük fel, hogy

inf · 2013. Okt. 21. (H), 14.52
Jó, de tegyük fel, hogy nulláról csinálsz egy saját keretrendszert... Mire lehetne áttérni?
Vannak wildcard visszatérő értékek, amik garantált, hogy kód duplikációhoz, és átláthatatlan kódhoz vezetnének.
Vannak kivételek, amik ha kezeletlenül maradnak, akkor a felhasználó csak pislog, hogy mivan.
Több lehetőséget nem látok...
64

Wildcard alatt nem tudom, mit

Joó Ádám · 2013. Okt. 22. (K), 14.39
Wildcard alatt nem tudom, mit értesz. Én több visszatérési értékű függvények egyik visszatérési értékeként adnék vissza státuszt, ami ugyanúgy lehetne egy kontextust (például stacktrace) magában foglaló objektum. Ehhez kellene egy rugalmas többes értékadás szintakszis, illetve a menthetetlen helyzetekre egy függvényhatárokon át működő goto-szerű konstrukció, amivel a mostani kivételkezeléshez hasonlóan ki lehetne ugrani egy kontextusból, de csak előre meghatározott helyre.
65

A wildcard alatt azt értem,

inf · 2013. Okt. 22. (K), 14.44
A wildcard alatt azt értem, ha mondjuk a null vagy false visszatérő érték jelenti a hibát. Ha több visszatérő érték lehet, az nyilván megoldja az ilyen jellegű problémát, de ez megint nyelv függő...

a menthetetlen helyzetekre egy függvényhatárokon át működő goto-szerű konstrukció, amivel a mostani kivételkezeléshez hasonlóan ki lehetne ugrani egy kontextusból, de csak előre meghatározott helyre.


A mostani kivétel kezelés miben más? Ha beteszem egy try-catch blokkba, akkor ugyanúgy goto, és meghatározott helyre ugrik...
70

A mostani kivételkezelés

Joó Ádám · 2013. Okt. 22. (K), 23.15
A mostani kivételkezelés abban különbözik, hogy nem kényszerít rá a kivétel elkapására.
69

Közben rájöttem, hogy

inf · 2013. Okt. 22. (K), 22.40
Közben rájöttem, hogy bizonyos kontextusban igazad lehet. Én túlságosan php-ban gondolkodtam, ott egy kezeletlen kivétel max egy felhasználóval cseszik ki, de olyan nyelveknél, ahol feláll a rendszer, és egyszerre szolgál ki több ezer embert, ott elég csúnya dolgokat tehet...
71

Ez az egyik része. A másik

Joó Ádám · 2013. Okt. 22. (K), 23.18
Ez az egyik része. A másik az, hogy külső erőforrások inkonzisztens állapotban maradhatnak. Gondolj egy adatbázisra, tranzakciókezelés nélkül.
72

Közben megnéztem a go-t, a

inf · 2013. Okt. 22. (K), 23.54
Közben megnéztem a go-t, a panic-recover-defer jól össze van rakva. A defer erőforrás felszabadításnál nagyon hasznos tudna lenni a try-catch mellett más nyelvekben is.

Az szerintem nem baj, hogy nem kényszerít rá a kivétel elkapásra. Azt szeretem én tudni, hogy hol akarom elkapni... Nyilván amin azt szeretném, hogy semmi ne menjen át, oda kiteszek egy catch Throwable-t, vagy go esetében üres interface-t fogok el, stb...
73

Közben megnéztem a go-t, a

BlaZe · 2013. Okt. 23. (Sze), 00.26
Közben megnéztem a go-t, a panic-recover-defer jól össze van rakva. A defer erőforrás felszabadításnál nagyon hasznos tudna lenni a try-catch mellett más nyelvekben is.

Ilyen pl javaban is van, végre. Már úgy értem, ami a try-catch végén felszabadítja az erőforrásokat. A finally ágban close-okkal szüttyögés eléggé határeset volt nagyüzemben :)

Az szerintem nem baj, hogy nem kényszerít rá a kivétel elkapásra. Azt szeretem én tudni, hogy hol akarom elkapni... Nyilván amin azt szeretném, hogy semmi ne menjen át, oda kiteszek egy catch Throwable-t, vagy go esetében üres interface-t fogok el, stb...

Pedig van, ahol ez jobb megfordítva, mármint hogy rákényszerít, hogy kapd el, max te továbbdobhatod, ha úgy látod jobbnak. Viszont explicit módon lekezelteti veled a hibát, az nem csapódhat bele váratlanul a szál tetejébe, vagy valahová egy jóval magasabb absztrakciós szinten, ahol nincs mód érdemben lekezelni a hibát. Javaban erre vannak a checked exceptionök. Erről ugye van vita, hogy jó, vagy sem. Szerintem speciel hasznos, lásd pl InterruptedException, vagy egyéb olyan exceptionök, amiket le KELL kezelnie a hívónak.
74

Nekem azért nem tetszik, mert

inf · 2013. Okt. 23. (Sze), 02.51
Nekem azért nem tetszik, mert túl hülyebiztosra tervezik, ami korlátozza az alkotói szabadságomat :-) Mondjuk a szál tetejéhez teszek egy bazi nagy try-catch blokkot, ami elkapja a kivételeket, aztán szépen mindent lekezelek egyszerre. Ha olyanom van, hogy nem indokolt a kód futásának a megszakítása valamilyen hibánál, akkor oda szintén beteszek egy try-catch-et, ami az adott hiba típust elkapja, és így tovább. Ha rákényszerítenek, hogy minden egyes függvénynél kapjam el a hibát, és utána dobjam tovább az baromi sok felesleges plusz munkával jár, amit nem szeretek, a kód meg nagy valószínűséggel nem lesz semmivel sem jobb minőségű...
76

Sztringet konvertálsz

Joó Ádám · 2013. Okt. 23. (Sze), 03.46
Sztringet konvertálsz integerré. Ha nem szám van benne, akkor hagyod, hogy abortáljon a kérés?
77

Ez mind szituáció függő. Pl

inf · 2013. Okt. 23. (Sze), 03.57
Ez mind szituáció függő. Pl ha számot várok, de szöveg jön a klienstől, akkor hagyom, hogy elszórja a kivételét, valahol fent meg elkapom, és küldök egy 400 - bad request választ. Ha nem fontos, akkor meg helyben kapom el a kivételt, amit dob, és ott kezelem a hibát.
99

A kivételkezelést akkor

tgr · 2013. Okt. 24. (Cs), 10.17
A kivételkezelést akkor használod, amikor egy részfolyamat képtelenné vált elvégezni a feladatát, ezért vissza kell adni a vezérlést a részfolyamatot hívó kódnak, és a részfolyamat nem tud visszaadni semmilyen hasznos információt (illetve a hibához kapcsolódókat igen, de az eredeti feladatához kapcsolódókat nem). Ennek egy speciális esete az, amikor a részfolyamat egyenlő az egész folyamattal, de ez egyáltalán nem szükségszerű.
52

Az egyedüli eszköz, aminek

Joó Ádám · 2013. Okt. 21. (H), 03.48
Az egyedüli eszköz, aminek nincs procedurális megfelelője az a throw és a try-catch.


Az Ada 1977-ben elsők közt vezette be a ma ismert kivételkezelést, hosszú-hosszú évekkel korábban, mint a polimorfizmust. Most akkor a kivételkezelés nem objektumorientált gyakorlat? Vagy a polimorfizmus nem szükséges feltétele az objektumorientáltságnak?

Mikor látjátok már be – és ez a válasz kifejezetten Gábornak is szól –, hogy semmi kézzelfoghatóról nem beszéltek? Típusosság, névterek, adatrejtés, interfészek, öröklődés, polimorfizmus, kivételkezelés: ezekről van értelme vitatkozni. Objektumorientáltságról és arról, hogy egy függvény argumentumát a függvény neve elé vagy mögé írjuk, nincs.
54

Így igaz

Pepita · 2013. Okt. 21. (H), 04.19
De én nem mertem volna ilyen ápertén leírni, abban nem is vagyok 100%-ig biztos, hogy OO-ról nincs értelme vitatkozni, de valóban a tulajdonságokról jóval több értelme van. Illetve hol van a határ az OO és a procedurális közt? Aki ezt egy éles kontúrvonallal meghúzza, az vagy egy Einstein, vagy téved. Szerintem.
Gábor, még nem láttam összeszedettebb procedurális kódodat, de majdnem a nyakam merném tenni rá, hogy akár ráfogható OO szemlélet. És erről vitázunk...

Igazad van, Ádám: ez így hülyeség. (Bocsánat! Szakmailag helytelent akartam mondani. :))
56

Pedig elég egyszerű

inf · 2013. Okt. 21. (H), 13.55
Pedig elég egyszerű szerintem. Objektum orientáltan objektumokat használsz és metódusokat hívsz rajtuk, procedurálisan pedig adatstruktúrákat, amiket függvényeknek adsz át. Ha vannak oo eszközök, akkor is néha jobban megéri adatstruktúrákat használni, feladat függő...

Amúgy a tipikus oo eszközök mindegyike kiváltható procedurálisan is valami hasonlóval, ez tényleg csak attól függ, hogy mennyire támogatja az ilyesmit az adott programnyelv. Pl adatrejtést closure-al, try-catch-et egy hasonló nyelvi elemmel, objektumokat olyan adatstruktúrával, amire closure-okat szórsz fel, és így tovább...
60

Mi az az objektum?

Joó Ádám · 2013. Okt. 21. (H), 14.13
Mi az az objektum?
61

Kb adat és függvények

inf · 2013. Okt. 21. (H), 14.45
Kb adat és függvények egységbe zárása úgy, hogy az adatrejtés elve érvényesül. Ha van closure egy olyan nyelvnél, ahol az objektumok nyelvi szinten nem támogatottak, akkor lehetőség van objektumok építésére, de onnantól, hogy objektumokat használunk, már nem procedurális programozásról beszélünk, hanem objektum orientáltról.

pl:

var createObject = function (data, functions){
	var object = {};
	var createMethod = function (func){
		return function (){
			return func.apply(data, arguments);
		};
	};
	for (var name in functions)
		object[name] = createMethod(functions[name]);
	return object;
};

var createClass = function (functions){
	return createObject({
		functions: functions
	}, {
		createInstance: function (data){
			var instance = createObject(data, this.functions);
			if (instance.init)
				instance.init();
			return instance;
		}
	});
};

var Hello = createClass({
	init: function (){
		this.message = "Hello "+this.recipient+"!";
	},
	render: function (){
		window.alert(this.message);
	}
});

var helloWorld = Hello.createInstance({
	recipient: "world"
});
var helloEverybody = Hello.createInstance({
	recipient: "everybody"
});
helloWorld.render();
helloEverybody.render();
66

Ezzel akkor azt mondod, hogy

Joó Ádám · 2013. Okt. 22. (K), 14.44
Ezzel akkor azt mondod, hogy az objektumorientáltság egyenlő az adatrejtéssel. Akkor miért vitatkoztok mindenféle más koncepciókról is? Miért nem csak az adarejtésről beszélgettek?
79

Talán azért, mert ezt végig

inf · 2013. Okt. 23. (Sze), 15.31
Talán azért, mert ezt végig kellett gondolni...

Van, akinek a procedurális programozásnál érvényes elvek sem tiszták, pl hogy miért fontos a kód újrahasznosítás vagy a kód olvashatósága... Hajlamosak ezeket az elveket, meg még egy csomó mást összemosni az objektum orientáltsággal. Az objektum orientáltság minden tulajdonsága teljes egészében következik a procedurális programozásból az encapsulation megkötésével.
78

Van más különbség is az oo

inf · 2013. Okt. 23. (Sze), 15.27
Van más különbség is az oo meg a procedurális szemlélet között. A procedurálisnál a függvények nincsenek kötve az adathoz, hanem egy fix helyen le vannak horgonyozva egy névtérben. Az objektum orientáltnál a metódusok az objektumhoz vannak kötve, és nem a névtérhez. Így ha mondjuk más algoritmus alapján akarjuk ugyanazt megcsinálni, akkor a procedurális szemléletnél két lehetőségünk van: lecseréljük a névteret, hogy a függvény nevek azonosak maradjanak vagy lecseréljük a függvény neveket. Az oo előnye ebben van, mert oo-nál elég csak az objektumot kicserélni, mert ahhoz vannak kötve a metódusok, nem pedig fixen a névtérhez. A polimorfizmus egyenes következménye az egységbe zárásnak. Sokan keverik az öröklődéssel, pedig öröklődés nélkül is lehet polimorfizmus, szimplán úgy, hogy két objektumnál ugyanazt az interface-t implementáljuk. Nem kell, hogy közös ősük legyen.

Szóval az objektum orientált programozást az különbözteti meg a procedurálistól, hogy van plusz egy megkötése: az egységbe zárás (encapsulation), az oo megközelítés minden egyéb jellemzője levezethető ebből. A procedurális elvek egy az egyben átemelhetőek oo-ra: kód újrahasznosítás, olvashatóság, stb... Ezek az encapsulation-el együtt a SOLID eleveket kényszerítik ki. A SOLID elvekből meg további elvek következnek. Egyelőre még jobban összeszedem a témát, aztán valamikor a télen írok cikket erről.
80

A procedurálisnál a

Joó Ádám · 2013. Okt. 23. (Sze), 15.47
A procedurálisnál a függvények nincsenek kötve az adathoz, hanem egy fix helyen le vannak horgonyozva egy névtérben. Az objektum orientáltnál a metódusok az objektumhoz vannak kötve, és nem a névtérhez. Így ha mondjuk más algoritmus alapján akarjuk ugyanazt megcsinálni, akkor a procedurális szemléletnél két lehetőségünk van: lecseréljük a névteret, hogy a függvény nevek azonosak maradjanak vagy lecseréljük a függvény neveket.
type angle ...
function sin(angle a) ...

type man ...
function sin(man m) ...
Amint látod, objektumorientáltság nélkül is köthető egy művelet az adathoz. Persze ha a nyelv nem támogatja a polimorfizmust, akkor fordítási időben fog eldőlni, hogy melyik művelet lesz végrehajtva. Az ún. objektumorientált nyelvek kiemelnek egy paramétert, a receiver-t, amin dynamic dispatch-et hajtanak végre. De ez csak egy önkényes tervezési megoldás, miért kellene egy paramétert kiemelten kezelni? A magam részéről fájdalmasan hiányolom a fősodorbeli nyelvekből a multiple dispatch-et, ami akár mindegyik paramétert polimorfan kezeli.

Száz szónak is egy a vége: ha feszegetjük, akkor mindig oda fogunk kilyukadni, hogy az obejtumorientáltság polimorfizmus. Minden más létezett már korábban is.
81

Száz szónak is egy a vége: ha

BlaZe · 2013. Okt. 23. (Sze), 17.44
Száz szónak is egy a vége: ha feszegetjük, akkor mindig oda fogunk kilyukadni, hogy az obejtumorientáltság polimorfizmus. Minden más létezett már korábban is.

Ezen az alapon azért a strukturált programozás se volt olyan fene nagy áttörés, mert a jmp/call/ret stb assemblyben, gépi kódban is létezik. Ha nagyon szigorúan akarjuk venni hogy milyen új elemeket vezetett be az OOP, akkor igazad van, a polimorfizmuson kívül nem nagyon hozott újdonságot, ami korábban nem volt megoldható valahogy. Viszont egyrészt ezeknek keretet adott, másrészt a programfejlesztés és tervezés menetét jelentősen megváltoztatta, és ez volt az igazi áttörés, nem a nyelvi elemek, amik ezt "csak" támogatják. Szerintem a fenti kijelentésed túlságosan is leegyszerűsíti a dolgokat.
82

Szerintem is leegyszerűsítő a

Joó Ádám · 2013. Okt. 23. (Sze), 18.23
Szerintem is leegyszerűsítő a kijelentésem, de úgy érzem, hogy rákényszerülök egy ilyen vitában. Arra próbálok rávilágítani mindezzel, hogy mesterséges az a szembenállás, ami mentén egy teljesen értelmetlen vitát folytat Gábor és Laci, ugyanis az objektumorientáltság az elmúlt 50-60 év programszervezési eredményeit összefoglaló fogalom. (Hozzátenném, hogy sajnos buzzword lett a fogalomból, ami nagyon sokat árt.) Gábor nem látja be, hogy ha úgy általában az objektumorientáltság létjogosultságát vitatja, akkor szinte minden jó gyakorlatot vitat; Laci pedig hogy ezek a jó gyakorlatok olyan nyelvekben is könnyen alkalmazhatók lehetnek, amik nem a ma dívó objektumorientált külsőségeket mutatják. Mindeközben sosem lehet tudni, hogy ki miről vitatkozik, mert egy rosszul definiált gyűjtőfogalmat emlegetnek, nem egy-egy nyelvi eszközt vagy technikát.
83

Már többször jeleztem az

Hidvégi Gábor · 2013. Okt. 23. (Sze), 18.58
Már többször jeleztem az utóbbi időben, hogy már csak a polimorfizmust és az öröklődést kritizálom, mégpedig azért, mert jelenlegi meglátásom szerint nagyon korlátozottan lehet ezeket használni, ennél jóval rugalmasabban lehet programozni például táblaorientált elvekkel. Az adatrejtésnek pedig – bizonyos nyelvekben, ahol hozzáférsz a forráskódhoz (pl. php, js) – egyszerűen nem látom értelmét ("jó, majd akkor nem érek hozzá, becsületszavamat adom"), de ha valakinek ez a heppje, és úgy gondolja, hogy ez bármitől is megvéd, sok boldogságot kívánok neki.
85

Már többször jeleztem az

BlaZe · 2013. Okt. 23. (Sze), 19.27
Már többször jeleztem az utóbbi időben, hogy már csak a polimorfizmust és az öröklődést kritizálom, mégpedig azért, mert jelenlegi meglátásom szerint nagyon korlátozottan lehet ezeket használni

Ezt alá tudod támasztani valamivel? Csak mert kb ez az egész buli lényege :) Aki OOP-ben programozik, igen erősen támaszkodik a polimorfizmusra, kb egész nap ezt használja. Szerintem valami félreértés van benned a fogalmat illetően.

Az adatrejtésnek pedig – bizonyos nyelvekben, ahol hozzáférsz a forráskódhoz (pl. php, js) – egyszerűen nem látom értelmét ("jó, majd akkor nem érek hozzá, becsületszavamat adom"), de ha valakinek ez a heppje, és úgy gondolja, hogy ez bármitől is megvéd, sok boldogságot kívánok neki.

Az adatrejtés nem irigységről, vagy arról szól, hogy "eldugjuk azt az integert, mert Igor a tundráról honnan tudhatná hogy kell vele bánni". Azért definiálunk kívülről "nem elérhető" tagokat, mert nem szeretnénk, ha azokat direkt módon kívülről megmódosíthatnák, ugyanis az az adott objektum inkonzisztens állapotához vezethet, és ki tudja milyen hibát fog okozni és mikor. Ehelyett az objektumok állapotát publikus metódusokon keresztül változtatjuk, ami biztosítja a konzisztens működést. Másrészt bármikor átírhatom interface változtatás nélkül az adott classt úgy, hogy az a változó kikerül, vagy más nevet kap benne. Tehát ezzel azt is biztosítjuk, hogy senki ne függjön egy objektum belső állapotán közvetlenül. Egyébként aki nagyon akarja, reflectionnel, vagy bizonyos nyelvekben byte code manipulációkkal úgyis hozzáférhet. De az ilyenért általában nádpálcás verés jár, néhány esetet kivéve.
90

Az adatrejtésről a 89-es

Hidvégi Gábor · 2013. Okt. 23. (Sze), 20.06
Az adatrejtésről a 89-es válaszomban írok.

Az öröklődést és a polimorfizmust most egy kalap alá veszem, és csak szimplán öröklődésként hivatkozom rájuk.

Az öröklődéssel az a bajom, hogy a világot statikusan modellezi le, mivel az adatok és a hozzájuk tartozó programlogika között erős kötés van. Ha változnak az adatok – márpedig változnak, mert a világ már csak ilyen, ha blogmotornál bonyolultabb alkalmazást készítünk –, akkor emiatt sokszor macerás átírni a programkódot, ha nem felel meg az eredeti interfésznek, erre hoztam példát múltkor. Laza csatolással jóval egyszerűbb és hatékonyabb a fejlesztés, az öröklődést legfeljebb a statikus, ritkán változó helyeken tudom elképzelni, mint a programlogika, erre volt példa pár hónappal ezelőtt az inf3rno által készített beléptető osztály.
93

Az öröklődéssel az a bajom,

BlaZe · 2013. Okt. 23. (Sze), 21.36
Az öröklődéssel az a bajom, hogy a világot statikusan modellezi le, mivel az adatok és a hozzájuk tartozó programlogika között erős kötés van.

Miben erősebb, vagy statikusabb ez a kötés, mint a strukturális programozásban? Én semmi különbséget nem látok az adat és a programkód közötti kapcsolatban. Mindkét esetben tudja a kód olvasni, meg írni. Az objektum belülről nézve nem más, mint egy strukturált program.

Ha változnak az adatok – márpedig változnak, mert a világ már csak ilyen, ha blogmotornál bonyolultabb alkalmazást készítünk –, akkor emiatt sokszor macerás átírni a programkódot, ha nem felel meg az eredeti interfésznek

Miért, a strukturált kód ezzel szemben átírja magát? :)

A példa, amit múltkor hoztál nem volt jó. Nyilván, amit admin módosítgathat kedvére, azt nem tesszük bele öröklési fába, mert értelmetlen. Többek között inf3rno írta le neked, hogy hogy kell ezt szépen megcsinálni OOP-ben. Illetve az olyan nyelvekben, ahol van többszörös öröklődés, ott megoldható másképp is, de pl a php nem ilyen.

A laza csatolás és a strukturált programozás ritkán fér meg egy mondatban, hisz konkrét implementáción függsz (függvényhívás), ami minden, csak nem laza csatolás. Persze van funcptr meg hasonlók, de alapvetően a strukturált programozás nagyon erős kötésekkel dolgozik. Ezzel szemben egy normálisan megírt OOP kódban nincsenek implementáción függések, kimondottan erre való pl az interface.

Lentebb láthatsz példát a laza csatolásra. Itt a TypePrinter osztály nem tud a Type interface egyetlen implementációjának létezéséről sem. Nem tudja hány van, kik azok, és mit csinálnak pontosan. Viszont bármelyik implementációjának ki tudja írni a nevét.
interface Type {
	public function getImplementationName(); 
}

class ConcreteType1 implements Type {
	public function getImplementationName() {
		return 'ConcreteType1';
	}
}

class ConcreteType2 implements Type {
	public function getImplementationName() {
		return 'ConcreteType2';
	}
}

class TypePrinter {
	public function printTypeName(Type $type){
		echo $type->getImplementationName();
	}
}

$typePrinter = new TypePrinter();
$typePrinter->printTypeName(new ConcreteType1());
$typePrinter->printTypeName(new ConcreteType2());
95

Az öröklődést és a

inf · 2013. Okt. 24. (Cs), 00.16
Az öröklődést és a polimorfizmust egyáltalán nem lehet egy kalap alá venni. Az öröklődés a polimorfizmusnak egy megnyilvánulási formája, amit viszonylag ritkán használnak. composition over inheritance
Az általad felvázolt problémára nem az öröklődés a megoldás, hanem a kompozit osztályok. Ezt le is írtuk legalább ketten.
86

Már beszéltünk az adatrejtés

Joó Ádám · 2013. Okt. 23. (Sze), 19.29
Már beszéltünk az adatrejtés lényegéről: itt nem a rossz szándékú manipuláció elleni védelemről van szó, hanem arról, hogy a fordító számára is érthetően dokumentáljuk azt, egy adott komponensből mi az, ami nyilvános, tehát hosszú távon támogatott, és mi az, ami bármikor változhat, tehát a komponensen kívül nem érdemes rá támaszkodni. Ezt lehet ad-hoc módon is jelölni, például a szöveges dokumentációban, megjegyzésben, nevezéktannal (aláhúzás a név előtt), de így, hogy a nyelv része, a fordító nem engedi, hogy használd, a generált dokumentációban megkülönböztethető stb. Tényleg nem látod ennek előnyét? Vagy te ha egy harmadik féltől származó komponenst használsz, abba bele szoktál irkálni?
89

Szerencsésnek mondhatom

Hidvégi Gábor · 2013. Okt. 23. (Sze), 19.47
Szerencsésnek mondhatom magam, mert már egy munkámban sem kell harmadik féltől származó komponenst használni, emiatt valóságos luxusban dolgozom, mert nem függök senkitől.

Korábban volt persze sok dolgom ilyenekkel, és mivel ezek készítői is emberek, és éltek a tévedéshez való jogukkal, ezért bele kellett nyúlnom a kódjukba, és ha láthatóságot kellett emiatt módosítani, nem volt különösebb lelkiismeretfurdalásom. Megtehettem, mert a forráskód nálam volt (js, php), és nem pl. lefordított C rutinkönyvtárról volt szó.
91

Szerencsésnek mondhatom

Joó Ádám · 2013. Okt. 23. (Sze), 20.11
Szerencsésnek mondhatom magam, mert már egy munkámban sem kell harmadik féltől származó komponenst használni, emiatt valóságos luxusban dolgozom, mert nem függök senkitől.


Apache és moduljai, PHP és kiterjesztései, a Zend motorhoz tartozó eszközök, MySQL, a szerkesztőd és egyéb eszközök, az operációs rendszered stb.

Korábban volt persze sok dolgom ilyenekkel, és mivel ezek készítői is emberek, és éltek a tévedéshez való jogukkal, ezért bele kellett nyúlnom a kódjukba, és ha láthatóságot kellett emiatt módosítani, nem volt különösebb lelkiismeretfurdalásom. Megtehettem, mert a forráskód nálam volt (js, php), és nem pl. lefordított C rutinkönyvtárról volt szó.


És ha érkezett egy új kiadása a komponensnek, akkor kikerested az összes módosításod, és újra belekódoltad a forrásba? Ahelyett, hogy írtál volna a komponenshez egy burkolót vagy még kevesebb munkával leszármaztattad volna az osztályaiból a sajátod (ugye a öröklődés haszontalansága), és amikor változik az eredeti, akkor elég kicsomagold és bemásold a régi helyére.

Nem láttam még soha a kódod, de egyre inkább azt a képed fested róla, hogy fenntarthatatlan.
92

Apache és moduljai, PHP és

Hidvégi Gábor · 2013. Okt. 23. (Sze), 20.23
Apache és moduljai, PHP és kiterjesztései, a Zend motorhoz tartozó eszközök, MySQL, a szerkesztőd és egyéb eszközök, az operációs rendszered stb.
Ezekkel érdekes módon soha nem volt problémám, legfeljebb akkor, ha verzióspecifikus kódot írtam, és az újabb változatban már nem működött (php, mysql).

És ha érkezett egy új kiadása a komponensnek, akkor kikerested az összes módosításod, és újra belekódoltad a forrásba?
Nem, dobtam ezeket a komponenseket, és megírtam inkább magam. Joel Spolskynak van valahol egy írása arról, hogy miért nem szeretnek belenyúlni a programozók mások kódjába (mert nem látják át teljesen).

Nem láttam még soha a kódod, de egyre inkább azt a képed fested róla, hogy fenntarthatatlan.
Eddig még működik : )
94

Az Ádám által felhozott

BlaZe · 2013. Okt. 23. (Sze), 22.10
Az Ádám által felhozott kétkedés mellett azt tenném még hozzá, hogy érdemes azon az aspektuson is elgondolkodnod, hogy a saját programod egyes részei is felhasználói a program többi részének, nem csak külső apikra igaz ez természetesen. Most az mindegy, hogy objektumokról, vagy bármi másról beszélünk. A lényeg, hogy ha több, független kódrész is módosíthatja közvetlenül ugyanazt a változót, az előbb-utóbb káoszhoz fog vezetni, és szinte követhetetlenné válik, hogy az adott változó milyen esetekben milyen értékeket vehet fel. És ha ebből kiesik egy hiba, akkor jöhet az ingujj feltűrése... Nyilván kódméret függvénye is, hogy mennyire nehéz elkapni egy ilyen hibát, de én speciel utálok ilyeneket nyomozni. Sok idő, és nem túl produktív. Az ügyfelek se örülnek neki. És ha többszálú programról beszélünk, akkor meg aztán igazán viccessé is válhat a helyzet. A hívó oldalon honnan tudod hogy lockolnod kell pl? És pláne honnan tudod, hogy hogy? Ha 2 különböző hívási helyen különböző módon lockolsz, akkor abból éjszakai pizzázás lesz :) És az igazi poén az egészben, hogy a hibát jó eséllyel csak éles környezetben fogod tapasztalni, random módon. Persze önmagában az adatrejtés ezen nem segít, de a probléma lokalizációjában nagy segítségre van.
96

És ha többszálú programról

inf · 2013. Okt. 24. (Cs), 00.21
És ha többszálú programról beszélünk, akkor meg aztán igazán viccessé is válhat a helyzet.


Erről egész könyveket írnak, be kellene küldeni a Fábry-nak, hogy adja elő :D
84

type angle ...function

inf · 2013. Okt. 23. (Sze), 19.26

type angle ...
function sin(angle a) ...
Ez nem adathoz kötése a függvénynek. Az adathoz kötés alatt azt értem, hogy az adaton keresztül hivatkozol rá, nem pedig a névtéren keresztül, amiben deklaráltad.

Egyáltalán nem mindegy, hogy

angle a = 15°
sin(a)
vagy

angle a = 15°
a.sin()
Az első esetben a névtér a kiindulópont a függvényre/metódusra hivatkozásnál, a második esetben az objektum a kiindulópont, amihez kötve van.
87

Mindenképpen a „névtéren”,

Joó Ádám · 2013. Okt. 23. (Sze), 19.37
Mindenképpen a „névtéren”, vagyis az adattípuson keresztül hivatkozol a függvényre. A függvények nincsenek benne minden egyes objektumban: amikor hivatkozol egy függvényre, akkor a futtatókörnyezet megnézi, hogy az adott adatstruktúra milyen típusba tartozik, és az arra a típusra adott néven definiált függvényt meghívja, egyik paramétereként az adatstruktúrát adva át. Mindez kései kötést feltételezve. Ha korai kötésről van szó, akkor futásidőben nem is kell ellenőrizni a típust, mert már fordítási időben eldől, hogy melyik függvény lesz meghívva.
88

Ez a része a dolognak

inf · 2013. Okt. 23. (Sze), 19.45
Ez a része a dolognak teljesen lényegtelen. Még alszok rá egyet, aztán holnap megfogalmazom, hogy miért nincs igazad.
97

A függvények nincsenek benne

inf · 2013. Okt. 24. (Cs), 03.16
A függvények nincsenek benne minden egyes objektumban: amikor hivatkozol egy függvényre, akkor a futtatókörnyezet megnézi, hogy az adott adatstruktúra milyen típusba tartozik, és az arra a típusra adott néven definiált függvényt meghívja, egyik paramétereként az adatstruktúrát adva át.


Ez technikailag nem számít. Ami számít, hogy először az objektumra hivatkozol, és attól kéred el a függvényt, amit használni akarsz. Amikor egy programnyelvet használsz, akkor általában az szokott érdekelni, hogy mit csinál a programnyelv, nem az, hogy hogyan csinálja azt.

Mivel oo-nál a függvények az objektumhoz vannak kötve, egy kódban egy objektum cseréjével az összes hozzá csatolt függvényt is ki tudod cserélni. Ezzel szemben procedurálisan az adatstruktúra cseréjével nem tudod kicserélni a függvényeket, amiket meghívsz rajta. Ez mind az encapsulation következménye. (Ebbe a fogalomba bele szokták keverni az adatrejtést is, pedig szerintem nem kéne. Adatrejtés nélkül is lehet objektum orientáltan programozni, pl javascriptben.)

Az encapsulation gyakorlatilag azt jelenti, hogy az adatstruktúra és az őt manipuláló függvények mindig együtt utaznak. Ezt lehet szimulálni procedurálisan úgy, hogyha closure-ként átadod az adatstruktúra mellett a hozzá tartozó függvényt is, amit használni akarsz rajta.

pl nézzük meg a szinuszos példát, van két algoritmusod, amelyeknek le szeretnéd mérni a sebességét, hogy dönteni tudjál, hogy melyiket használod:

function sin(angle x){
    sinus counter algorithm
}

function sinB(angle x){
    sinus counter B algorithm
}
Csinálsz méricskélő függvényeket.

function measureSinusAlgorithmSpeed(angle a){
/* tisztán mérést végző kód */
    timer t = new timer()
    t.start()
    sin(a)
    t.end()
    return 1/t.interval()
}
function measureSinusAlgorithmBSpeed(angle a){
/* tisztán mérést végző kód */
    timer t = new timer()
    t.start()
    sinB(a)
    t.end()
    return 1/t.interval()
}
measureSinusAlgorithmSpeed(30°)
measureSinusBAlgorithmSpeed(30°)
Mint látható a kód erősen ismétlődik, így nehezen karbantartható, még néhány új algoritmus, és valaki elkövet egy hibát, aztán lehet debuggolni ezerrel. A függvény hívásoknál is jelzi a problémát, hogy csak egy betűben tér el a két függvény neve, és jobban meg kell nézni a két hívást, hogy el tudjuk dönteni melyik melyik...

Hogyan oldható fel ez a kód ismétlődés?

A PHP alkotói ezeket a problémákat úgy szokták megoldani, hogy hozzácsapnak még egy flag-et a paraméter listához, ami alapján a függvény majd algoritmust választ:

function chooseSinusAlgorithmAndMeasureItsSpeed(angle a, string algorithm){
/* mérés indítása */
    timer t = new timer()
    t.start()
/* algoritmus választás */
    if (algorithm <> 'B')
        sin(a)
    else
        sinB(a)
/* mérést lezáró kód */
    t.end()
    return 1/t.interval()
}
foreach (['A','B'] as algorithm)
    chooseSinusAlgorithmAndMeasureItsSpeed(30°, algorithm)
Megszűnt az ismétlődés? Igen. Van valami zavaró a kódban?

Megváltozott a függvény neve. Azért lett hosszabb, mert a függvény már nem csak méréssel, hanem algoritmus választással is foglalkozik. (Általában nem jó dolog, ha egy függvény két dologgal foglalkozik. Ilyenkor a legjobb, ha mind a két dolgot leadja két másik függvénynek, és ő maga csak menedzseri funkciót lát el, szóval a két új függvény megfelelő sorrendben történő hívását.)
Ami még drámaibb lett, az a függvény törzse, amin a commentekből elég tisztán látszik, hogy az algoritmus választó kód szíven találta a mérést végző kódot. Így amikor valaki olvassa a függvény törzset, akkor gondolatmenetet kell váltania egy pillanatra, amikor az algoritmus választó kód fölé ér. Ez elég nyilvánvalóan csökkenti az érthetőségét a kódnak. (H. Gábornak: a kód olvashatóságát sor megértett kód / egységnyi idő-vel lehet mérni, aztán lehet átlagolni azzal, hogy sok embernek megmutatod a kódot.)

Hogyan tudnánk mégis újra leegyszerűsíteni?

Hát if-else helyett lehetne map-et használni (ha van closure a nyelvben), az egyszerűbb szerkezet:

function chooseSinusAlgorithmAndMeasureItsSpeed(angle a, string algorithm){
/* algoritmus választás */
    map algorithms = {A: sin, B: sinB}
    sin = algorithms[algorithm]
/* tisztán mérést végző kód */
    timer t = new timer()
    t.start()
    sin(a)
    t.end()
    return 1/t.interval()
}
foreach (['A','B'] as algorithm)
    chooseSinusAlgorithmAndMeasureItsSpeed(30°, algorithm)
A kód végülis tovább egyszerűsödött, de még mindig két dolgot csinál a függvény. Szedjük szét két al-függvényre:

function chooseSinusAlgorithm(string algorithm){
/* algoritmus választás */
    map algorithms = {A: sin, B: sinB}
    sin = algorithms[algorithm]
    return sin
}

function measureSinusAlgorithmSpeed(angle a, closure sin){
/* tisztán mérést végző kód */
    timer t = new timer()
    t.start()
    sin(a)
    t.end()
    return 1/t.interval()
}

function chooseSinusAlgorithmAndMeasureItsSpeed(angle a, string algorithm){
    closure sin = chooseSinusAlgorithm(algorithm)
    return measureSinusAlgorithmSpeed(a, sin)
}
foreach (['A','B'] as algorithm)
    chooseSinusAlgorithmAndMeasureItsSpeed(30°, algorithm)
Hogy lehetne még tovább egyszerűsíteni?

Tegyük fel magasabb absztrakciós szintre a menedzselést végző kódot:

function chooseSinusAlgorithm(string algorithm){
/* algoritmus választás */
    map algorithms = {A: sin, B: sinB}
    sin = algorithms[algorithm]
    return sin
}

function measureSinusAlgorithmSpeed(angle a, closure sin){
/* tisztán mérést végző kód */
    timer t = new timer()
    t.start()
    sin(a)
    t.end()
    return 1/t.interval()
}

foreach (['A','B'] as algorithm)
    measureSinusAlgorithmSpeed(30°, chooseSinusAlgorithm(algorithm))
Az algoritmus választást nem muszáj konstansok alapján csinálni, megcsinálhatjuk a closure direktben történő választásával:

function measureSinusAlgorithmSpeed(angle a, closure sin){
/* tisztán mérést végző kód */
    timer t = new timer()
    t.start()
    sin(a)
    t.end()
    return 1/t.interval()
}

foreach ([sin, sinB] as sin)
    measureSinusAlgorithmSpeed(30°, sin)
Mi is történt itt?

Az algoritmusra hivatkozó flag helyett magát az algoritmust adtuk át. Az algoritmus választást tehát egy magasabb absztrakciós szintre tettük, ahol ténylegesen csinálni akartuk, ahelyett, hogy a magasabb absztrakciós szinten megadott adatok alapján alacsonyabb absztrakciós szinten álltunk volna neki. Hogyan volt lehetséges mindez? Az adatok mellett átadtuk a függvényt is, ami manipulálni tudja őket. A mérést végző kódunk így teljes mértékben újrahasznosult, az egész kód pedig rugalmasan módosítható, mert ha egy új algoritmust adunk a rendszerhez, akkor az a measureSinusAlgorithmSpeed függvényre - aminek a kódja alacsony absztrakciós szintű - nem fog kihatni, a hatása megáll - egy magasabb absztrakciós szinten - a függvényhívás előtt a tesztelendő algoritmusok megadásánál. A polimorfizmus gyakorlatilag ezt a rugalmasan módosítható kódot jelenti, amiben csak azt kötjük meg, hogy mit csináljon a kód, azt már nem, hogy milyen algoritmus alapján csinálja. Így a függvények között laza csatolást tudunk biztosítani, nem lesz beégetve a kódba, hogy melyik függvény melyik másikat hívja. A polimorfizmus tehát ugyanúgy procedurális sajátság, mint minden más, ami előfordul objektum orientáltan. A procedurális és az objektum orientált megközelítés egyáltalán nem két egymással ellentétes dolog, hanem az objektum orientált a procedurális lehetőségeinek leszűkítése egy megkötéssel: az adatokat és az őket manipuláló függvényeket mindig egy egységbe zárjuk.

Nézzük meg mi történik objektum orientáltan a kóddal:

function sin(){this.n ...}
function sinB(){this.n ...}

function measureSinusAlgorithmSpeed(Object a){
/* tisztán mérést végző kód */
    timer t = new timer()
    t.start()
    a.sin()
    t.end()
    return 1/t.interval()
}

Object a = {n:30°}
foreach ([sin, sinB] as sin) {
    a.sin = sin
    measureSinusAlgorithmSpeed(a)
}
Az egységbe zárás miatt ugyanúgy sikerült átadni a sin algoritmusát, és ugyanúgy polimorf maradt a kód.

Külön algoritmus osztály használatával:

interface iSinAlgorithm {
    sin()
}
class SinA implements iSinAlgorithm  {
    setter Angle a 
    sin: function (){this.a ...}
}
class SinB implements iSinAlgorithm {
    setter Angle a 
    sin: function (){this.a ...}
}

function measureSinusAlgorithmSpeed(iSinAlgorithm s){
/* tisztán mérést végző kód */
    timer t = new timer()
    t.start()
    s.sin()
    t.end()
    return 1/t.interval()
}

numeric n = 30°
Angle a = new Angle(30°)
foreach ([new SinA(a), new SinB(a)] as sinAlgorithm)
    measureSinusAlgorithmSpeed(sinAlgorithm)
Angle osztályból örököltetéssel:

class Angle {
    setter numeric n
    toNumber: function (){...}
}
interface iSinAlgorithm {
    sin()
}
class AngleWithSinA extends Angle implements iSinAlgorithm  {
    sin: function (){this.n ...}
}
class AngleWithSinB extends Angle implements iSinAlgorithm {
    sin: function (){this.n ...}
}

function measureSinusAlgorithmSpeed(iSinAlgorithm s){
/* tisztán mérést végző kód */
    timer t = new timer()
    t.start()
    s.sin()
    t.end()
    return 1/t.interval()
}

numeric n = 30°
foreach ([new AngleWithSinA(n), new AngleWithSinB(n)] as angle)
    measureSinusAlgorithmSpeed(angle)
Angle + SinAlgorithm kompozícióval

interface iAngle {
    toNumber()
}
class Angle implements iAngle {
    setter numeric n
    toNumber: function (){...}
}
interface iSinAlgorithm {
    sin()
}
class SinAAlgorithm implements iSinAlgorithm {
    setter numeric n
    sin: function (){this.n ...}
}
class SinBAlgorithm implements iSinAlgorithm {
    setter numeric n
    sin: function (){this.n ...}
}
class SinAlgorithmAndAngleComposite implements iSinAlgorithm, iAngle {
    setter iAngle angle
    setter iSin sinAlgorithm {sinAlgorithm.n = angle.toNumber()}
    toNumber: angle.toNumber,
    sin: sinAlgorithm.sin
}

function measureSinusAlgorithmSpeed(iSinAlgorithm s){
/* tisztán mérést végző kód */
    timer t = new timer()
    t.start()
    s.sin()
    t.end()
    return 1/t.interval()
}

Angle a = new Angle(30°)
SinAngleComposite c = new SinAngleComposite()
c.angle = a
foreach ([new SinA(), new SinB()] as s) {
    c.sinAlgorithm = s
    measureSinusAlgorithmSpeed(c)
}
Mint látható, a measureSinusAlgorithmSpeed függvény törzse gyakorlatilag állandó maradt mindegyik oo megoldásnál. Egyedül a paraméter nevek változtak. Ez nyilván azért van, mert végig egy interface-t teljesített az átadott objektum: van egy sin függvény, ami visszaad egy sinus értéket. A closure-ként történő átadásnál a sin nevű változót használtuk ugyanerre a célra, szóval ott nem volt szükség még pluszban az interface megadására, hogy biztosítsuk a sin függvény meglétét.

Összességében tehát a polimorfizmus azt jelenti, hogy az adattal együtt az alacsonyabb absztrakciós szintű, algoritmust tartalmazó függvényt is átadjuk az őt hívó, magasabb absztrakciós szintű függvénynek. Így az alacsony szintű algoritmus cserélhető lesz anélkül, hogy a magasabb szintű függvény megváltozna. Tehát az ilyen jellegű kód könyebben karbantartható, az egyes függvények lazán csatoltak, és így tovább... A polimorfizmus nyelvtől, eszközöktől, programozási stílustól függően többféleképp megvalósítható. Az öröklés csak egy megvalósítás a sok közül. Az teljesen feladat függő, hogy éppen melyik megvalósítás a legjobb. Sok esetben nem az öröklés az.

Remélem kielégítő volt a válaszom. :-) Már megint 3 óra, hogy rohadna meg :D
98

Igen, ez pontosan az, amit

MadBence · 2013. Okt. 24. (Cs), 09.58
Igen, ez pontosan az, amit Ádám mondott (kései kötés), azaz hogy melyik konkrét metódus fog meghívódni, az futásidőben dől el a konkrét objektum típusától függően (dynamic dispatch).
100

Ádám azt mondta, hogy a

inf · 2013. Okt. 24. (Cs), 13.22
Ádám azt mondta, hogy a polimorfizmus oo sajátosság, illetve, hogy szerint az oo egyenlő a polimorfizmussal. Ezek az állítások nem igazak. Minden, ami az oo-ban jelen van procedurális sajátosság, mert az oo a procedurális megközelítés leszűkítése arra az esetre, amikor az adatok és a függvények egységbe zárva utaznak. A struktúrált programozás a procedurális leszűkítése arra az esetre, amikor az adatok és a függvények nem utaznak egységbe zárva. Legtöbbször ilyenkor csak az adatok utaznak, a függvények meg bele vannak égetve a kódba. Mindkét szemléletnek megvan a helye, ahol érdemes alkalmazni. Az oo-nak az az előnye, hogy könnyű új típust hozzáadni a polimorfizmus miatt, csak annyi az elvárás, hogy ugyanazt az interface-t implementálja, mint a többi. A struktúrált megközelítésnek az az előnye, hogy könnyű új függvényt hozzáadni, mert a függvények nincsenek kötve az adathoz. Pl oo-nál ha új metódust adsz egy interface-hez, akkor azt az összes osztályon implementálni kell, ami használja. Az emberek általában azt hiszik, hogy tisztán oo programoznak, pedig ez nem igaz, általában oo és struktúrált elemek is vannak a kódban. Vannak olyan programtervezési minták, amik kifejezetten struktúrált kódot írnak elő.
101

What is Object Oriented

Hidvégi Gábor · 2013. Okt. 24. (Cs), 13.39
What is Object Oriented Programming (OOP)?

Láttam-láttam, visszaélsz a szerkesztői jogosultságaiddal : )
102

Közel jár az igazsághoz, de

inf · 2013. Okt. 24. (Cs), 13.40
Közel jár az igazsághoz, de kellene még 1-2 kör mire teljesen átlátná. Én le tudom írni 1 mondatban, hogy mi az, hogy oop, ő le tudja írni egy oldalban. Elég nagy a különbség, nem? :-)
104

Csak finomítottam az

inf · 2013. Okt. 24. (Cs), 13.41
Csak finomítottam az álláspontomon. Általában azt vettem észre, hogy aki valamit nem tud tömören leírni, az csak kapizsgálja a témát, de még nem érti teljes egészében. Egy héttel ezelőttig én is csak használtam az oop-t, de fogalmam sem volt róla, hogy mi az.
105

Az encapsulation már a C-ben

Hidvégi Gábor · 2013. Okt. 24. (Cs), 13.44
Az encapsulation már a C-ben is megvolt, gondolj csak a static kulcsszóra, márpedig a C minden, csak nem OO nyelv.

Az a helyzet az OO-val (amire már Ádám is utalt párszor), hogy igazából senki sem tudja megfogalmazni, mi is pontosan, és innentől kezdve valóban nincs értelme mindenen vitatkozni.
107

Az encapsulation már a C-ben

inf · 2013. Okt. 24. (Cs), 13.54
Az encapsulation már a C-ben is megvolt, gondolj csak a static kulcsszóra, márpedig a C minden, csak nem OO nyelv.


Lövésem sincs a C-ről, mutasd, hogy mit tartasz encapsulation-nek!
109

Egy C programban ha egy

Hidvégi Gábor · 2013. Okt. 24. (Cs), 14.01
Egy C programban ha egy változónak vagy függvénynek a fájl érvényességi körén belül static kulcsszót is megadsz, akkor az csak az adott fájlban lesz látható.
110

Ennek semmi köze az

inf · 2013. Okt. 24. (Cs), 14.12
Ennek semmi köze az encapsulation-höz. Az encapsulation-nél az adathoz kötöd a függvényt, és az adatra hivatkozva éred el.
112

Ezt nem mindenki gondolja

Hidvégi Gábor · 2013. Okt. 24. (Cs), 14.44
Ezt nem mindenki gondolja így, a Wikipédia is hasonló példát hoz.
113

Encapsulation is used to hide

inf · 2013. Okt. 24. (Cs), 14.51
Encapsulation is used to hide the values or state of a structured data object inside a class


Rosszul gondolják, sokan keverik a data hidinggal, ami teljesen más fogalom.

wiki.object
Objects in "object-oriented programming" are essentially data structures together with their associated processing routines.


Ez írja le helyesen, hogy mi az, hogy encapsulation. Legalábbis szerintem. De én elfogadom, hogy mások szerint a data hiding egyenlő az encapsulation-el, viszont akkor én nem az encapsulation-re gondoltam, hanem arra, hogy az adat és a hozzá tartozó függvények együtt utaznak. Akkor erre gondolom nincs szaknyelvi szó.
114

Szvsz aki ezeket a fogalmakat

inf · 2013. Okt. 24. (Cs), 14.53
Szvsz aki ezeket a fogalmakat kitalálta, az baromi okos ember volt, csak sokan félreértették, félreértik ma is, hogy ezek a fogalmak mit jelentenek...
118

Ezeket nem egyvalaki találta

Joó Ádám · 2013. Okt. 24. (Cs), 16.05
Ezeket nem egyvalaki találta ki, ezek alapkoncepciók a programozásban, és sokkal régebbre mennek vissza. Ne ess abba a hibába, hogy egy bizonyos megvalósításukkal kevered őket össze, és félreértésnek bélyegzed az egyébként sokkal régebben létezőket, csak mert te ezen keresztül ismerted meg őket.
121

Én sem ezeken keresztül

inf · 2013. Okt. 25. (P), 10.38
Én sem ezeken keresztül értettem meg őket, de így lenne a logikus...
Van egy kérdésem a late binding-el kapcsolatban. Wikipedián azt írják róla, hogy az, hogy objektumokon keresztül érik el a függvényeket. Kérdés az, hogy akkor ha objektum helyett closure-t adok át, az is late binding e? A másik kérdés, hogyha van egy adatstruktúrám, és annak egy változójának closure-t állítok be, akkor vajon az is late binding e, ha azt utána meghívom, vagy az valami más? Nekem úgy lenne a logikus, ha a closure-t is dinamikusan kötnék a nyelvek, mert változóból mutatunk rá, nem valami statikus helyről, mint mondjuk egy névtér. Valószínűleg így is történik, de megerősítés kellene...

Btw ebben az esetben nem csak a polimorfizmus, hanem az encapsulation is a late binding következménye lenne. Ebből meg az következne, hogy annak, hogy az oo egyáltalán létezhessen, a late binding az alapja.
132

Van egy kérdésem a late

Joó Ádám · 2013. Okt. 25. (P), 13.07
Van egy kérdésem a late binding-el kapcsolatban. Wikipedián azt írják róla, hogy az, hogy objektumokon keresztül érik el a függvényeket.


Megnéztem a late bindinget, neked inkább a dynamic dispatch szócikk kell. Előbbi az utóbbi egy speciális esete.

Kérdés az, hogy akkor ha objektum helyett closure-t adok át, az is late binding e


Úgy általában a first class function feltétele a dynyamic dispatch, mert fordítási időben csak a függvény interfészére hivatkozol, futásidőben derül ki, milyen függvény van ott. Ezt írtam is egy másik hozzászólásban.

Btw ebben az esetben nem csak a polimorfizmus, hanem az encapsulation is a late binding következménye lenne.


Ezt nem látom, miért lenne így, de gondolom továbbra is JavaScriptben gondolkodsz :)
137

Ezt nem látom, miért lenne

inf · 2013. Okt. 25. (P), 15.36
Ezt nem látom, miért lenne így, de gondolom továbbra is JavaScriptben gondolkodsz :)


Nem, úgy általánosságban. De most már tisztult a kép.

dynamic dispatch -> polymorphism
dynamic dispatch -> closure
dynamic dispatch -> late binding -> object
data hiding + implementation hiding -> encapsulation
object + encapsulation -> class -> inheritance
object/class + polymorphism -> interface -> composition pattern
115

Nem, az adatrejtés és az

Joó Ádám · 2013. Okt. 24. (Cs), 15.49
Nem, az adatrejtés és az egységbezárás két összetartozó fogalom: nincs egységbezárás adatrejtés nélkül. Utóbbinak az a lényege, hogy meghatározza, mely műveletek férhetnek hozzá az adatrejtés hatálya alá tartozó információhoz. Adatrejtés nélkül az egységbezárás értelmezhetetlen fogalom, mert az adatokkal egység zárt műveleteket épp az különbözteti meg bármilyen más művelettől, ami az adott típusra van értelmezve, hogy az előbbiek privilegizáltak.
122

Értem, akkor én a late

inf · 2013. Okt. 25. (P), 10.41
Értem, akkor én a late binding objektumra vonatkozó fajtájával kevertem az encapsulation-t. Magának az encapsulation-nek, mint külön fogalomnak így semmi értelme, mert szinonímája lett az adatrejtésnek.
133

Egy másik aspektusát ragadja

Joó Ádám · 2013. Okt. 25. (P), 13.10
Egy másik aspektusát ragadja meg ugyanannak a jelenségnek.
117

De én elfogadom, hogy mások

Joó Ádám · 2013. Okt. 24. (Cs), 16.02
De én elfogadom, hogy mások szerint a data hiding egyenlő az encapsulation-el


Nem egyenlő, csak összatartozó, lásd a másik válaszom.

akkor én nem az encapsulation-re gondoltam, hanem arra, hogy az adat és a hozzá tartozó függvények együtt utaznak. Akkor erre gondolom nincs szaknyelvi szó.


És nem ejt gondolkodóba, hogy erre nincs szaknyelvi szó? :)
123

nem.

inf · 2013. Okt. 25. (P), 10.42
Nem. Az a helyzet, hogy teljesen tisztán látom az egész vázát, hogy mi mitől függ, csak a közös szótárat kellene valahogy ráillesztenem...
116

Pedig ez is encapsulation.

Joó Ádám · 2013. Okt. 24. (Cs), 16.01
Pedig ez is encapsulation. Itt is arról van szó, hogy az egységbezárással jelölöd ki azon függvények körét, amik az adatrejtés hatálya alá eső változókhoz hozzáférnek. A fordítási egységen kívül is létrehozhatsz olyan függvényeket, amik a modul nem statikus változóit használják, és ezek pont ugyanúgy fognak kinézni, mint a modul saját függvényei. A különbség az, hogy az utóbbiak hozzáférnek a statikus változókhoz.
124

Okés, akkor nem az

inf · 2013. Okt. 25. (P), 11.02
Okés, akkor nem az encapsulation-re gondoltam, hanem a late binding-ra. Beszéljünk egy kicsit erről. A wikipedia szerint egyedül a metódusok objektumhoz kötése, és azon keresztüli elérése a late binding. Szerintem viszont a closure-ok változóba tétele szintén late binding-nak számít. Mindkettőnek az az eredménye, hogy a függvényhívás dinamikusan, változón keresztül történik, és nem statikusan egy névtéren keresztül. A klasszikus oo nyelveknél még annyival megbolondítják a dolgot, hogy a metódusokat osztályokhoz kötik, az objektum meg az osztályra hivatkozva éri el őket, de ennek különösebb jelentősége nincs. Ami számít, hogy egy változó tartalmazza azt az információt, amin keresztül el lehet érni egy függvényt. A polimorfizmushoz csak ennyire van szükség, tehát ugyanúgy lehetséges objektumokkal is és closure-okkal is.

A closure-ok és objektumok meglétének feltétele a late binding. Már csak az a kérdés, hogy az encapsulation meg a data hiding miért nem ugyanazt jelent?
129

Szerintem az enkapszuláció

Hidvégi Gábor · 2013. Okt. 25. (P), 11.33
Már csak az a kérdés, hogy az encapsulation meg a data hiding miért nem ugyanazt jelent?
Szerintem az enkapszuláció része az implementációrejtés is. Azaz az az enkapszuláció részhalmaza a data hiding és az implementation hiding is.
134

Mindkettőnek az az eredménye,

Joó Ádám · 2013. Okt. 25. (P), 13.42
Mindkettőnek az az eredménye, hogy a függvényhívás dinamikusan, változón keresztül történik, és nem statikusan egy névtéren keresztül.


Static és dynamic dispatch esetén is a változón keresztül történik, mert a változónak/adatnak van típusa, és aszerint van kiválasztva a művelet. A különbség annyi, hogy statikus esetén fordításkor eldől, hogy melyik műveletről van szó, míg dinamikus esetén fordításkor csak egy kompatibilis típus van meghatározva, és bármelyik implementáció állhat ott futásidőben.

A klasszikus oo nyelveknél még annyival megbolondítják a dolgot, hogy a metódusokat osztályokhoz kötik, az objektum meg az osztályra hivatkozva éri el őket, de ennek különösebb jelentősége nincs.


Én nagyon azt érzem rajtad, hogy PHP-ban és JavaScriptben gondolkodsz. A típus fogalma szinte elválaszthatatlan a programozástól, mégis mellékes részletként kezeled. A néhány dinamikus nyelv is, amelyek nem használnak osztályokat, leírható típusokkal, hisz vehetjük úgy, hogy egy objektum meghatározza a más vagy saját osztályát (és a Ruby-ban például ez így is van, ha ad hoc bővítesz egy objektumot, akkor egy meta- vagy szellemosztály jön létre, amelynek leszármazottjává válik), de ha fordítva, a hagyományos nyelveket próbáljuk úgy kezelni, mintha csak objektumok volnának, hozzájuk csomagolt függvényekkel, akkor egy teljes a programozás elméletét támogató matematikai rendszert kidobnánk az ablakon. Szóval, szerintem a következő vállalkozásod legyen egy komoly típusrendszerrel rendelkező, statikus nyelv tanulmányozása :)
138

Ismerem a java-t. Nem tudom

inf · 2013. Okt. 25. (P), 15.38
Ismerem a java-t. Nem tudom az mennyire statikus.
108

Ádám azt mondta, hogy a

Joó Ádám · 2013. Okt. 24. (Cs), 13.59
Ádám azt mondta, hogy a polimorfizmus oo sajátosság, illetve, hogy szerint az oo egyenlő a polimorfizmussal.


Variáljuk egy kicsit meg: azt mondtam, hogy az oo sajátossága a polimorfizmus. Az az egyetlen dolog, ami korábban nem létezett, és amitől az oo más, mint a jó strukturált kód.

az oo a procedurális megközelítés leszűkítése arra az esetre, amikor az adatok és a függvények egységbe zárva utaznak. A struktúrált programozás a procedurális leszűkítése arra az esetre, amikor az adatok és a függvények nem utaznak egységbe zárva.


A strukturált programozás az imperatív programozásra épít a blokkstruktúra bevezetésével. Az objektumorientált programozás a strukturált programozásra épít a polimorfozmus bevezetésével. A jó strukturált kód és az objektumorientált kód között az egyetlen különbség, hogy utóbbiban futásidőben (igen, az „objektumhoz kötve”) dől el, hogy melyik függvény lesz meghívva, fordítási időben egy interfész az adat típusa.

Az oo-nak az az előnye, hogy könnyű új típust hozzáadni a polimorfizmus miatt, csak annyi az elvárás, hogy ugyanazt az interface-t implementálja, mint a többi. A struktúrált megközelítésnek az az előnye, hogy könnyű új függvényt hozzáadni, mert a függvények nincsenek kötve az adathoz.


Nem, azért könnyű új függvényt hozzáadni, mert adott típushoz adod csak hozzá, nem egy interfészhez, amit több osztály implementál. Azt hiszem, egyébként látom, mi vész téged tévútra. Írj erre az utóbbira egy példát légyszi! (Tudom, hogy máshol már írtál egyszer, de most nem keresem meg, és lehetőleg te se, csak írd, ami egyből eszdbe jut.)
111

Variáljuk egy kicsit meg: azt

inf · 2013. Okt. 24. (Cs), 14.26
Variáljuk egy kicsit meg: azt mondtam, hogy az oo sajátossága a polimorfizmus. Az az egyetlen dolog, ami korábban nem létezett, és amitől az oo más, mint a jó strukturált kód.


Igen, de ez nem igaz, mert closure-ban ugyanúgy átadható egy függvény az adattal párhuzamosan, és máris polimorf lesz a kód. Nézd végig a szinuszos példákat... A polimorfizmus pusztán annak a következménye, hogy egy függvényre lehet változón keresztül relatívan hivatkozni, és nem kell névtéren keresztül abszolút hivatkozni rá.

global.f = function (){}

function staticCaller(){
    global.f()
}
staticCaller()

function polimorfCaller(f){
    local.f()
}
polimorfCaller(global.f)
Nem, azért könnyű új függvényt hozzáadni, mert adott típushoz adod csak hozzá, nem egy interfészhez, amit több osztály implementál. Azt hiszem, egyébként látom, mi vész téged tévútra. Írj erre az utóbbira egy példát légyszi! (Tudom, hogy máshol már írtál egyszer, de most nem keresem meg, és lehetőleg te se, csak írd, ami egyből eszdbe jut.)


Én pont hogy az ellenkezőjét írtam. Azért nehéz új függvényt hozzáadni, mert utána az összes osztályban implementálni kell.

oo

interface iAngle {}
class AngleInDegrees implements iAngle {

}
class AngleInRadians implements iAngle {

}

->

interface iAngle {
    sin()
}
class AngleInDegrees implements iAngle {
    sin: function (){...}
}
class AngleInRadians implements iAngle {
    sin: function (){...}
}
struktúrált

class AngleInDegrees {}
class AngleInRadians {}

->

function sin(AngleInDegrees a){...}
A struktúráltnál nem muszáj megadni az AngleInRadians -ra is a szinusz függvényt, ezért könnyebb új függvényt hozzádni. Objektum orientáltan viszont muszáj megadni, különben nem fogja implementálni az interface-t, és elszáll hibával. Ez végülis nem is feltétlen az oo és struktúrált közötti különbség, hanem a polimorf és nem polimorf közötti különbség, az oo viszont az adat és a függvény kötése miatt mindig polimorf.
120

A struktúráltnál nem muszáj

Joó Ádám · 2013. Okt. 24. (Cs), 16.29
A struktúráltnál nem muszáj megadni az AngleInRadians -ra is a szinusz függvényt, ezért könnyebb új függvényt hozzádni. Objektum orientáltan viszont muszáj megadni, különben nem fogja implementálni az interface-t, és elszáll hibával.


Az objektumorientáltnál sem muszáj megadni a másikra, csak akkor, ha interfészen keresztül akarsz rá hivatkozni. Ha csak az egyik konkrét osztályon akarod használni, akkor ahhoz adod meg. Ugyanez a helyzet a strukturáltnál: ha csak az egyiknél kell, csak arra írod meg, ha kell mindkettőhöz, akkor mindkettőhöz meg kell írd.

az oo viszont az adat és a függvény kötése miatt mindig polimorf


Ez nem igaz. C++-ban az osztály adatot rejt (az adattagokhoz nem férhetsz hozzá külső függvényből) és egységbezár (az osztállyal együtt deklarált függvényekből hozzáférhetsz), mégis külön kell jelöld a polimorf függvényeket. Azt hiszem, ez mutatja a legjobban azt, hogy rosszul értelmezed az egységbezárást.
125

Szóval az interface jelöli ki

inf · 2013. Okt. 25. (P), 11.08
Szóval az interface jelöli ki a polimorf függvények körét... Closure-ok esetében viszont nincs szükség interface-re, mert a változódban csak a closure-t adod át...

Nem értelmezem rosszul az egységbezárást, csak a hozzá kapcsolódó szavak jelentése nem világos. Leginkább az adatrejtést és az encapsulation-t kellene tisztázni.

Nekem az jött le, hogy az encapsulation a függvények egy részének elrejtését jelenti, mert azt mondtátok, hogy oo nélkül is már volt... Ha így definiáljuk, akkor viszont nem tartozik bele az adatok elrejtése egy objektumban, illetve az objektumok megléte sem szükséges feltétele. Ehhez képest mindenki úgy hivatkozik rá, mint oo fogalom, meg hogy az adatrejtés is része... Na most akkor mi a helyzet vele?
135

Closure-ok esetében viszont

Joó Ádám · 2013. Okt. 25. (P), 13.51
Closure-ok esetében viszont nincs szükség interface-re, mert a változódban csak a closure-t adod át...


Megint dinamikus nyelvekben gondolkodsz: a függvénynek is van típusa, interfésze, és ahol függvényt adsz át egy változóban, ott a változó típusa ez a típus.

Nekem az jött le, hogy az encapsulation a függvények egy részének elrejtését jelenti, mert azt mondtátok, hogy oo nélkül is már volt... Ha így definiáljuk, akkor viszont nem tartozik bele az adatok elrejtése egy objektumban, illetve az objektumok megléte sem szükséges feltétele. Ehhez képest mindenki úgy hivatkozik rá, mint oo fogalom, meg hogy az adatrejtés is része... Na most akkor mi a helyzet vele?


Műveletet és adatot is rejthetsz el és tehetsz hozzáférhetővé, illetve rendelhetsz egymáshoz. Az, hogy itt egy modulról vagy egy objektumról van szó, lényegtelen, általános elvekről beszélünk. Egy függvény esetén is érvényesül az információrejtés, mert nem láthatsz bele. Azért hivatkoznak rá oo fogalomként, mert manapság a csapból is az oo folyik.
139

Szóval az encapsulation

inf · 2013. Okt. 25. (P), 15.39
Szóval az encapsulation gyakorlatilag azt jelenti, hogy van külön stack-je a függvénynek, és nem csak globális változókat tud használni? Már ha jó értelemben használom a stack szót :D

A dynamic dispatch azt jelenti, hogy változó tárolhat függvényt?
141

Egy függvény esetén azt

Joó Ádám · 2013. Okt. 25. (P), 15.56
Egy függvény esetén azt jelenti az adatrejtés, hogy kívülről nem férsz hozzá a lokális változókhoz. Csak azt akartam megmutatni, hogy az adatrejtés egy általános elv, amit nagyon sok kontextusban lehet alkalmazni.

A dynamic dispatch azt jelenti, hogy futásidőben, egy indirekción keresztül dől el, hogy melyik függvény hívódik meg, míg static dispatch esetén fordításkor egy bizonyos függvény címe kerül a hívás helyére. Az adott nyelv szempontjából nem változó tárolja, nem arról van szó, hogy bekerül egy változóba a függvény, hanem arról, hogy az adat mellett a rendszer metainformációként tárol egy mutatót a típusra, ahol megtalálható a függvény címe. Ez persze az implementáció szempontjából egy változó. Az implementált nyelv szemszögéből ez része a változónak.
103

Mivel oo-nál a függvények az

Joó Ádám · 2013. Okt. 24. (Cs), 13.41
Mivel oo-nál a függvények az objektumhoz vannak kötve, egy kódban egy objektum cseréjével az összes hozzá csatolt függvényt is ki tudod cserélni. Ezzel szemben procedurálisan az adatstruktúra cseréjével nem tudod kicserélni a függvényeket, amiket meghívsz rajta. Ez mind az encapsulation következménye.


Nem, ez nem az encapsulation, hanem a polimorfizmus következménye, ugyanis az az, ami fordítási időben megelégszik egy interfésszel, és futási időben dönti el a valódi típust és megfelelő függvényt.

Nagyon jól le tudod vezetni ezeket a koncepciókat, csak ez most nem vágott ide. Inkább cikkbe érdemes annak, aki nem érti, mint egy hozzászólásba nekem :)

Mivel minden objektum egy osztály példánya, ezért az, hogy az objektumhoz tartozik a függvény vagy a típushoz, kívülről szerintem nem megállapítható. Azt kérdezem akkor, hogy te miért tartod lényegesnek, hogy koncepcionálisan az objektumhoz tartozónak tekintsük? Szemben azzal, hogy az obkektumhoz csak egy típus tartozik, ami meghatároz egy műveletet.
106

Nem, ez nem az encapsulation,

inf · 2013. Okt. 24. (Cs), 13.52
Nem, ez nem az encapsulation, hanem a polimorfizmus következménye, ugyanis az az, ami fordítási időben megelégszik egy interfésszel, és futási időben dönti el a valódi típust és megfelelő függvényt.


Valóban ezt írtam le, de ez nem oo sajátság, a closure-nak is sajátsága mindez, ami meg nem szükségszerűen oo. A polimorfizmus valóban a late binding miatt lehetséges.

Mivel minden objektum egy osztály példánya, ezért az, hogy az objektumhoz tartozik a függvény vagy a típushoz, kívülről szerintem nem megállapítható. Azt kérdezem akkor, hogy te miért tartod lényegesnek, hogy koncepcionálisan az objektumhoz tartozónak tekintsük? Szemben azzal, hogy az obkektumhoz csak egy típus tartozik, ami meghatároz egy műveletet.

o.f = function (){}
o.f()

C = {
    f: function (){}
}
o.Class = C
o.f = o.Class.f.bind(o)
o.f()
Mindegyik az objektumtól kiindulva érhető el, az, hogy milyen útvonalon, teljesen lényegtelen. Ezért írtam, hogy az, hogy ezt részleteiben hogyan valósítják meg az adat - függvény kötést, nem számít. A lényeg a programozásban, amikor egy kódot használunk, mindig az, hogy mit csinál az a kód, nem az, hogy hogyan csinálja...
119

Valóban ezt írtam le, de ez

Joó Ádám · 2013. Okt. 24. (Cs), 16.21
Valóban ezt írtam le, de ez nem oo sajátság, a closure-nak is sajátsága mindez, ami meg nem szükségszerűen oo.


Legyünk pontosak, a zárvány itt irreleváns, az első rendű függvény a lényeg. Az pedig a ploimorfizmus egy megnyilvánulása: fordítási időben egy függvény interfészt (visszatérési típus, paraméterek száma és típusa) adsz meg, majd futási időben dől el, hogy pontosan melyik implementációját, melyik függvényt kell hívni. Ez az, ami C-ben is működik, annak ellenére, hogy a nyelv az adatok viszonyában nem ismeri a polimorfizmust.

Mindegyik az objektumtól kiindulva érhető el, az, hogy milyen útvonalon, teljesen lényegtelen. Ezért írtam, hogy az, hogy ezt részleteiben hogyan valósítják meg az adat - függvény kötést, nem számít. A lényeg a programozásban, amikor egy kódot használunk, mindig az, hogy mit csinál az a kód, nem az, hogy hogyan csinálja...
int square(int i) {
    return i * i;
}

int i = 2;

int j = square(i);
Itt van egységbezárás?
126

Attól függ, hogy mit nevezel

inf · 2013. Okt. 25. (P), 11.11
Attól függ, hogy mit nevezel egységebe zárásnak.
127

Az adatokat és a rajtuk

Hidvégi Gábor · 2013. Okt. 25. (P), 11.22
Az adatokat és a rajtuk műveleteket végző függvények összességét.
128

Az előbb azt írtad, hogy

inf · 2013. Okt. 25. (P), 11.24
Az előbb azt írtad, hogy "Szerintem az enkapszuláció része az implementációrejtés is." szóval attól nem lettem okosabb, hogy leírsz két tök különböző dolgot, és mindkettőre azt mondod, hogy az az egységbe zárás...
130

Pontosítottam fentebb.

Hidvégi Gábor · 2013. Okt. 25. (P), 11.35
Pontosítottam fentebb.
131

Ha csak adat és implementáció

inf · 2013. Okt. 25. (P), 11.53
Ha csak adat és implementáció rejtést jelenti, akkor ez független a late binding-tól, és semmi köze az objektumokhoz. Max annyi, hogy oo-nál objektumokon használják...

Az oo akkor se nem polimorfizmus, se nem encapsulation. Az oo objektumokkal dolgozik, az objektum meg az adatok és az őket manipuláló függvényeket tartalmazó egység. Az egységbe zárás és a polimorfizmus az objektumoktól teljesen függetlenül létező fogalmak. A polimorfizmusnak elég, ha vannak objektumok. Az encapsulation-t viszont meg kell támogatni plusz egy nyelvi elemmel, ha objektumokon akarjuk használni, vagy closure-al, vagy ppp osztállyal.
136

Ha csak adat és implementáció

Joó Ádám · 2013. Okt. 25. (P), 13.55
Ha csak adat és implementáció rejtést jelenti, akkor ez független a late binding-tól, és semmi köze az objektumokhoz. Max annyi, hogy oo-nál objektumokon használják...


Így van.

Az oo objektumokkal dolgozik, az objektum meg az adatok és az őket manipuláló függvényeket tartalmazó egység.


Ezt hívják típusnak ;)
58

Az Ada 1977-ben elsők közt

inf · 2013. Okt. 21. (H), 14.05
Az Ada 1977-ben elsők közt vezette be a ma ismert kivételkezelést, hosszú-hosszú évekkel korábban, mint a polimorfizmust.

Ez a része már túlhaladott a vitának, közben rájöttem én is, hogy procedurális nyelvekben is van kivétel kezelés.

Mikor látjátok már be – és ez a válasz kifejezetten Gábornak is szól –, hogy semmi kézzelfoghatóról nem beszéltek? Típusosság, névterek, adatrejtés, interfészek, öröklődés, polimorfizmus, kivételkezelés: ezekről van értelme vitatkozni.

Én is kb ugyanerre a konklúzióra jutottam. Teljesen nyelv függő, hogy milyen eszközöket biztosítanak procedurális programozáshoz. Általában ha van oo támogatás, akkor ahhoz alapból erősebb eszközöket adnak. Nem értem, hogy miért ez a megkülönböztetés, de ez van.
33

Az olvashatóság teljesen

BlaZe · 2013. Okt. 19. (Szo), 21.35
Az olvashatóság teljesen szubjektív dolog

Ez nem állja meg teljesen a helyét, illetve max addig, amíg egyedül dolgozol. Ugyanis az olvashatóság nem a kód készítőjének fontos igazán (ő ismeri jól - egy darabig), hanem annak, aki utána bele fog nyúlni. Többek között ezért nem tartunk olvashatónak pl egy többszáz soros függvényt, az ugyanis igen nagy valószínűséggel több absztrakciós réteget fog kilapítani, és emiatt az olvasóját felesleges részletekkel terheli, nehezebb kihámozni belőle azt, ami érdekli. Majd a fordító kilapítja a kódot, ahogy neki tetszik. Ez mondjuk nem kimondottan csak OOP probléma, de segíteni segít benne, mivel erősen támogatja az absztrakciós szintenkénti tagoltságot (öröklődés, polimorfizmus). Aztán ezt vagy (túl)használod, vagy nem.

Ami az első cikket illeti, jól hangzik, és divat a mai modern eszközök utálása, hogy bezzeg a régi időkben. Bezzeg a régi időkben nem írtunk ilyen összetett rendszereket. Kicsit megváltozott a szoftverfejlesztés, és az új igények új, bonyolultabb toolokat, és magasabb szintű nyelveket igényelnek. Rakj össze egy komolyabb rendszerintegrációs projectet egy sima editorban egy alacsonyszintű programozási nyelvben, web service libek, ESB, MQ, meg minden nélkül. És ha itt még nem lőtted fejbe magad, akkor refaktorálj egyet :) Garantáltan kihullik a hajad. Hogy a fejlesztést támogató eszközöket meg kell tanulni használni, és azok komplexebbek egy szögegyszerű editoról? Hát... az élet kemény :)
35

OOP-ben is lehet írni

Hidvégi Gábor · 2013. Okt. 20. (V), 08.11
OOP-ben is lehet írni többszázsoros függvényt, és ki lehet lapítani legalább ugyanannyi absztrakciós réteget, ugyanúgy, mint procedurálisban, ez csak a készítőn múlik. Az, hogy van öröklődés és polimorfizmus, ezt nem fogja meggátolni, de segíteni sem.

Linuxon rengeteg rutinkönyvtár C-ben készül a mai napig, nagy projektek is, ahol aztán nincs (közvetlenül) OOP, mégis olvasható, karbantartható kódot gyártanak, legalábbis most szúrópróbaszerűen belenéztem a libXML2 forrásába pár helyen.
55

Az, hogy van öröklődés és

Joó Ádám · 2013. Okt. 21. (H), 04.43
Az, hogy van öröklődés és polimorfizmus, ezt nem fogja meggátolni, de segíteni sem.


Az ilyen kijelentéseket szoktad mérlegelni? Az öröklődés épp arról szól, hogy megspórolja neked egy interfész implementálását, az újrahasznosítani kívánt osztály példányosítását, és rengeteg függvénydefiníciót, ami semmi mást nem csinál, mint közvetít ehhez a példányhoz. A polimorfizmus pedig a típusellenőrzést végző elágazásokat iktatja ki a kódból. Úgy gondolod, hogy ezek nem segítenek olvashatóbbá és strukturáltabbá tenni a kódot?

Linuxon rengeteg rutinkönyvtár C-ben készül a mai napig, nagy projektek is, ahol aztán nincs (közvetlenül) OOP, mégis olvasható, karbantartható kódot gyártanak


Feltételezem, hogy soha nem fejlesztettél érdemben C-ben. A dolog ott kezdődik, hogy vagy olyan függvény- és struktúraneveket használsz, amik körülbelül egy numerikus azonosító olvashatóságával vetekednek, vagy félképernyőnyi lesz minden azonosító, hisz nincsenek névterek, és a szignatúrának nem része az argumentumlista, így két különböző típushoz nem használhatod ugyanazt a függvénynevet. C-ben nincs polimorfizmus, de nincsenek típusok sem futásidőben, úgyhogy ha valaha is szükséged lenne rá, hogy különböző típusú elemeket tárolj egy tömbben, akkor találj ki nekik egy azonosítót (ízlés szerint egy random numerikus konstanst vagy egy újabb kilométeres enumot), amit kézzel tárolj el mindegyik bejegyzés mellé. De mivel öröklődés sincs, ezért ha egy meglévő típust szeretnél kiterjeszteni, akkor jöhet a fent leírt kálvária az újradeklerálással és közvetítéssel. Mielőtt még lesöpörnéd azzal, hogy ezeket te úgysem használod, de, te is használod, csak a legkevésbé biztonságos és a legrosszabb teljesítményű megoldással, asszociatív tömbökkel. Na, C-ben olyanok nincsenek, úgyhogy még te is kénytelen lennél új típusokat definiálni. A konstruktorok és destruktorok hiányát még nem is említettem, természetesen az inicializációt és az erőforrások felszabadítását is kézzel kell végezni, utóbbiba természetesen a memóriakezelés is beletartozik. A tény, hogy függvényeket kizárólag a felső szinten lehet definiálni nem sokat segít a kód strukturálásán, és tovább terheli az amúgy is telített globális névteret…
63

Az első részhez: mint írtam,

Hidvégi Gábor · 2013. Okt. 22. (K), 08.44
Az első részhez: mint írtam, az olvashatóság és a strukturálás teljesen szubjektív, amit leírsz, az is csak ezt erősíti, mert valaki így szereti, más meg amúgy. Például nem mindenki számára lesz olvashatóbb a kód, ha a konvenciót követve külön fájlokba darabolod a kódot, így, ha meg szeretnéd érteni, mindegyiken egyesével végig kell menni. Vannak emberek, akik jobban átlátják az if () {} elseif () {} else {} szerkezetet, mert egy helyen van, végigsiklik rajta a szemük, és át is látják. Nem is beszélve arról, hogy az öröklődésnél ÉS kapcsolat van az öröklöttek között, míg if-es szerkezetnél lehet ilyen is: if (változó1 or változó2) {} elseif ((változó3 and változó4) or változó5) {}

Feltételezem, hogy soha nem fejlesztettél érdemben C-ben.
Ez így van, de ez nem is számít, mert php-ban is úgy fejlesztettem mindig is, mint C-ben. Gigantikus méretű projekteken sem dolgoztam eddig, és emiatt igazából elképzelni sem tudom, hogy mikor lehet szükség névterekre, hisz, ha modulárisan dolgozol, miért lenne két függvénynek, osztálynak vagy változónak ugyanaz a neve?

C-ben a legnagyobb probléma a memóriakezelés, dehát másnak is sikerült már abszolválnia. Egyébként pont most tervezek ismét nekifutni annak, hogy folytassam a php-s projektem átírását C-re.
68

Nem is beszélve arról, hogy

BlaZe · 2013. Okt. 22. (K), 21.24
Nem is beszélve arról, hogy az öröklődésnél ÉS kapcsolat van az öröklöttek között, míg if-es szerkezetnél lehet ilyen is: if (változó1 or változó2) {} elseif ((változó3 and változó4) or változó5) {}

Ebből mit szeretnél kihozni? Nem értem. Valóban, az öröklés nem if. A polimorfizmusnak pont az a lényege, hogy ne kelljen teletömni a kódodat ifekkel. Sőt, a túl sok ifet egyenesen tervezési hibának tartják.

Gigantikus méretű projekteken sem dolgoztam eddig, és emiatt igazából elképzelni sem tudom, hogy mikor lehet szükség névterekre, hisz, ha modulárisan dolgozol, miért lenne két függvénynek, osztálynak vagy változónak ugyanaz a neve?

Pedig dolgoztál olyan projecteken, ahol te is használtál névtereket, max nem vetted észre :)
24

Eddig még senki sem tudta

inf · 2013. Okt. 19. (Szo), 15.06
Eddig még senki sem tudta bebizonyítani, hogy az OO-tól olvashatóbb, karbantarthatóbb lenne a kód


Pedig az.
28

Tévedés. OO környezetben

MadBence · 2013. Okt. 19. (Szo), 17.01
Tévedés. OO környezetben számos olyan best practice (patternek, stb) van, amivel könnyű (könnyebb) karbantartható kódot írni (illetve mivel pl ezek a minták elég elterjedtek, olvasni is könnyebb őket). De ez nem ad garanciát, csak egy eszközt, amit vagy jól használsz vagy nem (lásd SimplePHPEasyPlus, FizzBuzzEnterpriseEdition).
31

Az overengineering egyáltalán

inf · 2013. Okt. 19. (Szo), 20.46
Az overengineering egyáltalán nem oo-val kapcsolatos hiba. Egyszerűen túlgondolja, túláltalánosítja a problémát. Ugyanúgy procedurálisan is el lehet követni. A TDD egy elég jó megoldás ennek az elkerülésére.
19

Egyszerűség, hatékonyság

pkadam · 2013. Okt. 19. (Szo), 08.15
Lehet, hogy egy adott műveletet egyszerűbb megérteni, ha bőbeszédűbb a kód, de a kód egészét könnyebb úgy átlátni, ha rövid és tömör a műveletek meghívása.

Ráadásul időhatékonyság szempontjából is jobbnak látok egy result(0,'Hiba!') sort, hiszen rövidebb leírni, vagyis ezzel a megközelítéssel gyorsabban végezhető a munka. Egy új fejlesztő csatlakozása esetén még mindig kevesebb idő egyszer ránézni a függvényre és megérteni azt, mint mindent már a futás helyén megérteni – elvégre ha megértésre csak egyszer van szükség, minek bonyolítsuk a kódot minden egyes meghívásnál?

Én látom az OOP létjogosultságát, leginkább akkor, amikor egyes függvények csak adott kontextusban használatosak, így ilyenkor indokolatlan a globális névtérbe tolni őket. Csak az nem világos, hogy hívhatjuk-e OOP-nek azt, hogy ha bizonyos dolgok objektumok, így vannak metódusaik, de ezek mellett használunk globálisan függvényeket is általános célra, procedurálisan?
26

Lehet, hogy egy adott

inf · 2013. Okt. 19. (Szo), 15.32
Lehet, hogy egy adott műveletet egyszerűbb megérteni, ha bőbeszédűbb a kód, de a kód egészét könnyebb úgy átlátni, ha rövid és tömör a műveletek meghívása.


Eleve nem is szoktunk ilyet leírni, hogy result(0, 'Hiba!'), inkább olyanok szoktak lenni, hogy throw new Error('Hiba!'), vagy throw new UnknownError(). Ugyanolyan tömör a dolog, csak felesleges konstansok nélkül, pusztán osztálynevekkel. Procedurálisan is lehet valami hasonlót csinálni, pl return error\unknown(), vagy bármi ilyesmi... Nyilván procedurálisan nehezebb, mert nincs try-catch blokk.

Egy új fejlesztő csatlakozása esetén még mindig kevesebb idő egyszer ránézni a függvényre és megérteni azt, mint mindent már a futás helyén megérteni – elvégre ha megértésre csak egyszer van szükség, minek bonyolítsuk a kódot minden egyes meghívásnál?


Ez egyáltalán nem igaz. Senkinek sincs olyan jó memóriája, hogy fejből tudja az összes projektjénél, hogy melyik milyen függvényeket használ, és melyik függvénynek mi a pontos paraméter listája. Én személy szerint már 1-2 hét után el szoktam felejteni, ha nem foglalkozom az adott projekttel.

Igazából egyik válasz sem arról szól, hogy érdemes e oo-t használni, hanem arról, hogy érdemes e olvasható kódot írni. Érdemes. Ha nem hiszed, akkor olvass el pár könyvet ezzel kapcsolatban.

Személy szerint én úgy gondolom, hogy oo-val könnyebb olvasható kódot írni, mint procedurálisan, köszönhető ez az oo megközelítéssel kapcsolatos nyelvi elemeknek: class, interface, extends, implements, new, instanceof, try-catch-finally, final, protected, private, public, stb... A névterek nem tartoznak ide, azt lehet oo nélkül is, szóval a globális névtér beszennyezése nem indokolja az oo-t. Nyilván ezeket a plusz nyelvi elemeket nem úri passzióból találták ki, hanem azért, mert megkönnyítik a munkát. Ha ezt valaki nem látja be, akkor tőlem nyugodtan írhat procedurális kódot, engem nem zavar, csak ne kerüljön a szemem elé soha a projektje, mert akkor általában a hajamat szoktam tépni...
29

Mostanra megint nagyon elkanyarodtunk

Pepita · 2013. Okt. 19. (Szo), 17.54
A srác OO-t akar tanulni, hát segítsünk neki. Ha a szándéka megvan (márpedig ebben nincs hiány), akkor a legegyszerűbb példától érdemes indulni, hogy értse. Aztán egyszer csak "beüt" a nagy haszon, onnantól még WC-re is OO megy... :) Akkor persze visszább kell húzni, ne maradjon a ló másik felén.
De itt vitatkozbi arról, hogy jó-e neki - teljesen értelmetlen, mert meg akarja tanulni.
45

Csak hogy valami

inf · 2013. Okt. 20. (V), 15.50
Csak hogy valami konstruktívabb dolog is történjen ebben a témában, elkezdtem rendszerezni kicsit az alap kódot.

Kiszedtem pár dolgot, pl a tábla nevét a config-ból, a sablon string-eket onnan, ahol egyáltalán nincs rájuk szükség, sőt úgy általában mindenhonnan:

<?php  
session_start();  
  
$host='localhost'; // Host név  
$username=''; // Mysql felhasználónév  
$password=''; // Mysql jelszó   
$db_name='test'; // adazbázis név  
  
// Csatlakozás az adatbázishoz  
mysql_connect($host, $username, $password)or die('cannot connect');   
mysql_select_db($db_name)or die('cannot select DB');  
  
// Felhasználó és jelszó tárolás változókban  
$myusername=$_POST['myusername'];   
$mypassword=$_POST['mypassword'];   
  
// Injection szürés  
$myusername = stripslashes($myusername);  
$mypassword = stripslashes($mypassword);  
$myusername = mysql_real_escape_string($myusername);  
$mypassword = mysql_real_escape_string($mypassword);  
$result=mysql_query('SELECT * FROM members WHERE username=\''.$myusername.'\' and password=\''.$mypassword.'\'');  
  
// Ha egyeznek az adatok belép és mentjük az adatokat sessionban  
if(mysql_num_rows($result)){  
	session_register('myusername');  
	session_register('mypassword');   
	header('location:valami.php')  
}  
else {  
	echo 'Hibás jelszó vagy felhasználónév.'; 
	include('urlap.php');
}  

Átírtam mysqli templatek használatára, hogy biztosan ne lehessen injektálni. Nem tudom, hogy a mysql_real_escape_string miben rossz, de azt mondják, hogy injektálható.

<?php  
session_start();  
  
$host='localhost'; // Host név  
$username=''; // Mysql felhasználónév  
$password=''; // Mysql jelszó   
$db_name='test'; // adazbázis név  
  
// Csatlakozás az adatbázishoz  
mysqli_connect($host, $username, $password, $db_name)or die('cannot connect');   
  
// Felhasználó és jelszó tárolás változókban  
$myusername=$_POST['myusername'];   
$mypassword=$_POST['mypassword'];   
  
// Injection szürés  
$stmt=mysqli_prepare('SELECT * FROM members WHERE username=? and password=?') or die('cannot reach db');  
mysqli_stmt_bind_param($stmt, 'ss', $myusername, $mypassword) or die('cannot reach db');
mysqli_stmt_execute($stmt) or die('cannot reach db');
  
// Ha egyeznek az adatok belép és mentjük az adatokat sessionban  
if(mysqli_stmt_num_rows($stmt)){  
	session_register('myusername');  
	session_register('mypassword');   
	header('location:valami.php')  
}  
else {  
	echo 'Hibás jelszó vagy felhasználónév.'; 
	include('urlap.php');
}  
Feloldottam a változónév ütközésből adódó problémákat a config és az input esetében:

<?php  

session_start();  
  
$config = array(
	'host' => 'localhost',
	'username' => '',
	'password' => '',
	'database' => 'test'
);

  
// Csatlakozás az adatbázishoz  
mysqli_connect($config['host'], $config['username'], $config['password'], $config['database'])or die('nem sikerült kapcsolódni');   
  
// Felhasználó és jelszó tárolás változókban  
$input = array(
	'username' => $_POST['username'],
	'password' => $_POST['password']
);
  
// Injection szürés  
$stmt=mysqli_prepare('SELECT * FROM members WHERE username=? and password=?') or die('nem sikerült elérni az adatbázist');  
mysqli_stmt_bind_param($stmt, 'ss', $input['username'], $input['password']) or die('nem sikerült elérni az adatbázist');
mysqli_stmt_execute($stmt) or die('nem sikerült elérni az adatbázist');
  
// Ha egyeznek az adatok belép és mentjük az adatokat sessionban  
if(mysqli_stmt_num_rows($stmt)){  
	session_register('myusername');  
	session_register('mypassword');   
	header('location:valami.php')  
}  
else {  
	echo 'Hibás jelszó vagy felhasználónév.'; 
	include('urlap.php');
}  

Átírtam a hibakezelést, hogy könnyen cserélhető legyen a hibaüzenet:

<?php  

define('DB_INIT_ERROR', 501);
define('DB_QUERY_ERROR', 502);
define('UNAUTHORIZED', 401);
  
set_error_handler(function ($errno, $type, $errfile, $errline)  
{  
    if ($errno != E_USER_ERROR)  
        return false;  
	if ($type === DB_INIT_ERROR)
		echo 'Adatbázis kapcsolódási hiba.';
	else if ($type === DB_QUERY_ERROR)
		echo 'Lekéréssel kapcsolatos hiba.';
	else if ($type === UNAUTHORIZED) {
		echo 'Hibás jelszó vagy felhasználónév.'; 
		include('urlap.php');
	}
	else
		echo 'Ismeretlen hiba.';
    return true;  
});  
  
session_start();  
  
$config = array(
	'host' => 'localhost',
	'username' => '',
	'password' => '',
	'database' => 'test'
);

  
// Csatlakozás az adatbázishoz  
mysqli_connect($config['host'], $config['username'], $config['password'], $config['database']) or trigger_error(DB_INIT_ERROR, E_USER_ERROR);
  
// Felhasználó és jelszó tárolás változókban  
$input = array(
	'username' => $_POST['username'],
	'password' => $_POST['password']
);
  
// Injection szürés  
$stmt=mysqli_prepare('SELECT * FROM members WHERE username=? and password=?') or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
mysqli_stmt_bind_param($stmt, 'ss', $input['username'], $input['password']) or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
mysqli_stmt_execute($stmt) or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
  
// Ha egyeznek az adatok belép és mentjük az adatokat sessionban  
if(mysqli_stmt_num_rows($stmt)){  
	session_register('myusername');  
	session_register('mypassword');   
	header('location:valami.php')  
}
else
	trigger_error(UNAUTHORIZED, E_USER_ERROR); 
Beszórtam az egész kódot egyetlen controller függvénybe, ezek után már csak ezzel a függvénnyel foglalkozok:

<?php  

define('DB_INIT_ERROR', 501);
define('DB_QUERY_ERROR', 502);
define('UNAUTHORIZED', 401);
  
set_error_handler(function ($errno, $type, $errfile, $errline)  
{  
    if ($errno != E_USER_ERROR)  
        return false;  
	if ($type === DB_INIT_ERROR)
		echo 'Adatbázis kapcsolódási hiba.';
	else if ($type === DB_QUERY_ERROR)
		echo 'Lekéréssel kapcsolatos hiba.';
	else if ($type === UNAUTHORIZED) {
		echo 'Hibás jelszó vagy felhasználónév.'; 
		include('urlap.php');
	}
	else
		echo 'Ismeretlen hiba.';
    return true;  
});  
  
function loginController(){
	session_start();  
	  
	$config = array(
		'host' => 'localhost',
		'username' => '',
		'password' => '',
		'database' => 'test'
	);

	  
	// Csatlakozás az adatbázishoz  
	mysqli_connect($config['host'], $config['username'], $config['password'], $config['database']) or trigger_error(DB_INIT_ERROR, E_USER_ERROR);
	  
	// Felhasználó és jelszó tárolás változókban  
	$input = array(
		'username' => $_POST['username'],
		'password' => $_POST['password']
	);
	  
	// Injection szürés  
	$stmt=mysqli_prepare('SELECT * FROM members WHERE username=? and password=?') or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
	mysqli_stmt_bind_param($stmt, 'ss', $input['username'], $input['password']) or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
	mysqli_stmt_execute($stmt) or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
	  
	// Ha egyeznek az adatok belép és mentjük az adatokat sessionban  
	if(mysqli_stmt_num_rows($stmt)){  
		session_register('myusername');  
		session_register('mypassword');   
		header('location:valami.php')  
	}
	else
		trigger_error(UNAUTHORIZED, E_USER_ERROR); 
}
loginController();
Szétszedtem témakörök szerint függvényekre a loginController-t:

function getConfig(){
	return array(
		'host' => 'localhost',
		'username' => '',
		'password' => '',
		'database' => 'test'
	);
}

function parseLoginFormInput(){
	return array(
		'username' => $_POST['username'],
		'password' => $_POST['password']
	);
}

function getDatabaseConnection(array $config){
	mysqli_connect($config['host'], $config['username'], $config['password'], $config['database']) or trigger_error(DB_INIT_ERROR, E_USER_ERROR);
}

function findUserByIdentificationFactors(array $factors){
	$stmt=mysqli_prepare('SELECT * FROM members WHERE username=? and password=?') or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
	mysqli_stmt_bind_param($stmt, 'ss', $factors['username'], $factors['password']) or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
	mysqli_stmt_execute($stmt) or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
	return $stmt;
}

function authenticate($stmt){
	if(mysqli_stmt_num_rows($stmt)){  
		session_register('myusername');  
		session_register('mypassword');   
		header('location:valami.php')  
	}
	else
		trigger_error(UNAUTHORIZED, E_USER_ERROR); 
}
  
function loginController(){
	session_start();  
	  
	$config = getConfig();

	  
	// Csatlakozás az adatbázishoz  
	getDatabaseConnection($config);
	  
	$input = parseLoginFormInput();
	  
	// Injection szürés  
	
	$stmt = findUserByIdentificationFactors($input);
	// Ha egyeznek az adatok belép és mentjük az adatokat sessionban  
	authenticate($stmt);
}
Töröltem a commenteket, feleslegesek, mert a függvénynevek megmondják, hogy mi történik:

function loginController(){
	session_start();  
	$config = getConfig();
	getDatabaseConnection($config);
	$input = parseLoginFormInput();
	$stmt = findUserByIdentificationFactors($input);
	authenticate($stmt);
}
Ha megnéznénk több controller-t, akkor kiderülne, hogy a session_start, getConfig és a getDatabaseConnection ismétlődő dolgok, ezeket ki lehet emelni a loginController-ből egy magasabb szintre:

function loginController(){
	$input = parseLoginFormInput();
	$stmt = findUserByIdentificationFactors($input);
	authenticate($stmt);
}

function router(){
	session_start();  
	$config = getConfig();
	getDatabaseConnection($config);
	if ($_SERVER['REQUEST_URI'] == '/login.php')
		loginController();
	else if (...)
		...
	...
}
router();
Hogy a router tényleg csak az url alapján történő kérés elosztást csinálja, ezeket az ismétlődő részeket még feljebb kell tenni:

function router(){
	if ($_SERVER['REQUEST_URI'] == '/login.php')
		loginController();
	else if (...)
		...
	...
}

function bootstrap(){
	session_start();  
	$config = getConfig();
	getDatabaseConnection($config);
	router();
}

bootstrap();
Ezek után, hogy csak a szükséges függvények kerüljenek beolvasásra minden kéréskor, érdemes htaccess-be beletenni, hogy a bootstrap.php-ra irányítson minden esetben, kivéve persze a statikus fájloknál. Ezt hívják font controller mintának.

RewriteEngine On
RewriteCond %{REQUEST_URI}  !(\.png|\.jpg|\.gif|\.jpeg|\.bmp)$
RewriteRule (.*)  bootstrap.php [QSA]
Ezek után a bootstrap és a routing így alakul:

bootstrap.php

<?php

define('DB_INIT_ERROR', 501);
define('DB_QUERY_ERROR', 502);
define('UNAUTHORIZED', 401);
  
set_error_handler(function ($errno, $type, $errfile, $errline)  
{  
    if ($errno != E_USER_ERROR)  
        return false;  
	if ($type === DB_INIT_ERROR)
		echo 'Adatbázis kapcsolódási hiba.';
	else if ($type === DB_QUERY_ERROR)
		echo 'Lekéréssel kapcsolatos hiba.';
	else if ($type === UNAUTHORIZED) {
		echo 'Hibás jelszó vagy felhasználónév.'; 
		include('urlap.php');
	}
	else
		echo 'Ismeretlen hiba.';
    return true;  
});  
  
function getConfig(){
	return array(
		'host' => 'localhost',
		'username' => '',
		'password' => '',
		'database' => 'test'
	);
}

function getDatabaseConnection(array $config){
	mysqli_connect($config['host'], $config['username'], $config['password'], $config['database']) or trigger_error(DB_INIT_ERROR, E_USER_ERROR);
}


function router(){
	if ($_SERVER['REQUEST_URI'] == '/login.php') {
		require_once('login.php');
		loginController();
	}
	else if (...)
		...
	...
}

function bootstrap(){
	session_start();  
	$config = getConfig();
	getDatabaseConnection($config);
	router();
}

bootstrap();

Így most már foglalkozhatunk a controller részével a dolognak.

login.php

<?php  

function parseLoginFormInput(){
	return array(
		'username' => $_POST['username'],
		'password' => $_POST['password']
	);
}

function findUserByIdentificationFactors(array $factors){
	$stmt=mysqli_prepare('SELECT * FROM members WHERE username=? and password=?') or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
	mysqli_stmt_bind_param($stmt, 'ss', $factors['username'], $factors['password']) or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
	mysqli_stmt_execute($stmt) or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
	return $stmt;
}

function authenticate($stmt){
	if(mysqli_stmt_num_rows($stmt)){  
		session_register('myusername');  
		session_register('mypassword');   
		header('location:valami.php')  
	}
	else
		trigger_error(UNAUTHORIZED, E_USER_ERROR); 
}
  
function loginController(){
	$input = parseLoginFormInput();
	$stmt = findUserByIdentificationFactors($input);
	authenticate($stmt);
}
Magának az authenticate-nek a jelentése az identitiás ellenőrzése, szóval a valami.php-re irányítás, és a session-be mentés nem feltétlen kell, hogy része legyen a dolognak, a felhasználó megtalálása az azonosító faktorok alapján viszont igen. Rendezzük át a kódot:

function authenticate(array $factors){
	$stmt = findUserByIdentificationFactors($factors);
	if(!mysqli_stmt_num_rows($stmt))  
		trigger_error(UNAUTHORIZED, E_USER_ERROR); 
}
  
function loginController(){
	$input = parseLoginFormInput();
	authenticate($input);
	session_register('myusername');  
	session_register('mypassword');   
	header('location:valami.php')  
}

Ha most megnézzük a loginController-t, akkor elég világosan látható, hogy van benne egy kis logikai hiba. Nem a felhasználói nevet és jelszót szokták letárolni session-ben, hanem a felhasználó id-jét. Az authenticate-nek tehát a user id-t kellene visszaadni. Módosítsuk a kódot e szerint.

login.php

<?php  

function parseLoginFormInput(){
	return array(
		'username' => $_POST['username'],
		'password' => $_POST['password']
	);
}

function findUserByIdentificationFactors(array $factors){
	$stmt=mysqli_prepare('SELECT userid FROM members WHERE username=? and password=?') or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
	mysqli_stmt_bind_param($stmt, 'ss', $factors['username'], $factors['password']) or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
	mysqli_stmt_execute($stmt) or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
	$userid = null;
	if (mysqli_stmt_num_rows($stmt)){
		mysqli_stmt_bind_result($stmt, $userid);
		mysqli_stmt_fetch($stmt);
		mysqli_stmt_close($stmt);
	}
	return $userid;
}

function authenticate(array $factors){
	$userid = findUserByIdentificationFactors($factors);
	if(!isset($userid))  
		trigger_error(UNAUTHORIZED, E_USER_ERROR); 
	return $userid;
}
  
function loginController(){
	$input = parseLoginFormInput();
	$userid = authenticate($input);
	session_register('userid', $userid);  
	header('location:valami.php')  
}

Ezek után szét lehet választani a kódot két részre. Az egyik rész a böngészővel tartja a kapcsolatot, és az onnan jövő adatokat ellenőrzi, a másik rész az adatbázissal tartja a kapcsolatot.

login.php

<?php  

require_once('login_model.php');

function parseLoginFormInput(){
	return array(
		'username' => $_POST['username'],
		'password' => $_POST['password']
	);
}
  
function loginController(){
	$input = parseLoginFormInput();
	$userid = authenticate($input);
	session_register('userid', $userid);  
	header('location:valami.php')  
}
login_model.php

<?php

function findUserByIdentificationFactors(array $factors){
	$stmt=mysqli_prepare('SELECT userid FROM members WHERE username=? and password=?') or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
	mysqli_stmt_bind_param($stmt, 'ss', $factors['username'], $factors['password']) or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
	mysqli_stmt_execute($stmt) or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
	$userid = null;
	if (mysqli_stmt_num_rows($stmt)){
		mysqli_stmt_bind_result($stmt, $userid);
		mysqli_stmt_fetch($stmt);
		mysqli_stmt_close($stmt);
	}
	return $userid;
}

function authenticate(array $factors){
	$userid = findUserByIdentificationFactors($factors);
	if(!isset($userid))  
		trigger_error(UNAUTHORIZED, E_USER_ERROR); 
	return $userid;
}
A végeredmény így:
  • .htaccess - front controller (mindent a bootstrap.php-re irányít)
    
    RewriteEngine On
    RewriteCond %{REQUEST_URI}  !(\.png|\.jpg|\.gif|\.jpeg|\.bmp)$
    RewriteRule (.*)  bootstrap.php [QSA]
    
  • bootstrap.php - hibakezelés, konfigurálás, adatbázis kapcsolat, routing, ezeket még mind-mind külön fájlokba lehetne tenni témakörök szerint
    
    <?php
    
    define('DB_INIT_ERROR', 501);
    define('DB_QUERY_ERROR', 502);
    define('UNAUTHORIZED', 401);
      
    set_error_handler(function ($errno, $type, $errfile, $errline)  
    {  
        if ($errno != E_USER_ERROR)  
            return false;  
    	if ($type === DB_INIT_ERROR)
    		echo 'Adatbázis kapcsolódási hiba.';
    	else if ($type === DB_QUERY_ERROR)
    		echo 'Lekéréssel kapcsolatos hiba.';
    	else if ($type === UNAUTHORIZED) {
    		echo 'Hibás jelszó vagy felhasználónév.'; 
    		include('urlap.php');
    	}
    	else
    		echo 'Ismeretlen hiba.';
        return true;  
    });  
      
    function getConfig(){
    	return array(
    		'host' => 'localhost',
    		'username' => '',
    		'password' => '',
    		'database' => 'test'
    	);
    }
    
    function getDatabaseConnection(array $config){
    	mysqli_connect($config['host'], $config['username'], $config['password'], $config['database']) or trigger_error(DB_INIT_ERROR, E_USER_ERROR);
    }
    
    
    function router(){
    	if ($_SERVER['REQUEST_URI'] == '/login.php') {
    		require_once('login.php');
    		loginController();
    	}
    	else if (...)
    		...
    	...
    }
    
    function bootstrap(){
    	session_start();  
    	$config = getConfig();
    	getDatabaseConnection($config);
    	router();
    }
    
    bootstrap();
    
  • login.php - loginController, loginFormParser, még magát az urlap.php-t is bele lehetne emelni, ha el lehetne kapni az UNAUTHORIZED típusú hibát ezen a szinten (sajnos ez php-ben procedurálisan nem támogatott)
    
    <?php  
    
    require_once('login_model.php');
    
    function parseLoginFormInput(){
    	return array(
    		'username' => $_POST['username'],
    		'password' => $_POST['password']
    	);
    }
      
    function loginController(){
    	$input = parseLoginFormInput();
    	$userid = authenticate($input);
    	session_register('userid', $userid);  
    	header('location:valami.php')  
    }
    
  • login_model.php - authenticate, findUserByIdentificationFactors
    
    <?php
    
    function findUserByIdentificationFactors(array $factors){
    	$stmt=mysqli_prepare('SELECT userid FROM members WHERE username=? and password=?') or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
    	mysqli_stmt_bind_param($stmt, 'ss', $factors['username'], $factors['password']) or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
    	mysqli_stmt_execute($stmt) or trigger_error(DB_QUERY_ERROR, E_USER_ERROR); 
    	$userid = null;
    	if (mysqli_stmt_num_rows($stmt)){
    		mysqli_stmt_bind_result($stmt, $userid);
    		mysqli_stmt_fetch($stmt);
    		mysqli_stmt_close($stmt);
    	}
    	return $userid;
    }
    
    function authenticate(array $factors){
    	$userid = findUserByIdentificationFactors($factors);
    	if(!isset($userid))  
    		trigger_error(UNAUTHORIZED, E_USER_ERROR); 
    	return $userid;
    }
    


Ha ez a része megy, akkor el lehet kezdeni foglalkozni az oop-vel. A php-ben az oop ennél annyival nyújt többet, hogy
  • van try-catch blokk, tehát az UNAUTHORIZED típusú hibát a loginController-ben el lehet kapni, és ott kirajzolni a urlap.php-t. Akár még ugyanabba a fájlba is be lehet tenni az urlap.php kódját, mint amiben a parseLoginFormInput van, így egymás mellett lesz az űrlap kirajzolása, és az elküldött űrlap input-jainak beolvasása.
  • Lehetőség van a hiba osztály definíciójában megadni, hogy hogyan rajzolja ki saját magát, így nem kell szétválogatni hibakód szerint a hibakezelőben, elég csak egy render-t meghívni az aktuális példányra.
  • Van autoload, így require, include, stb... nélkül automatikusan be lehet olvastatni az egyes fájlokat, és akár minden osztály külön fájlba kerülhet, és biztosan csak azokat a kódrészeket tölti be a rendszer, amelyekre tényleg szükség van. Ha van opcode cache a rendszerben, akkor így akár még kicsivel gyorsabb is lehet az oo kód, mint a procedurális.
  • Van névtér, így tovább lehet kategorizálni a dolgokat, pl a login.php anyaga a Controller névtérbe kerülhet, a login_model.php anyaga pedig a Model névtérbe. Ez egyébként procedurálisan is elérhető lehetőség, csak most nem használtam. Annyiban jelent könnyebbséget az ilyesfajta rendszerezés, hogy nem lesznek ömlesztve a fájlok, hanem névterek szerint külön mappákba lehet tenni őket. Ennek akkor van jelentősége, ha nagy a rendszer, és sok fájl van. Így egyszerűbb elkerülni a név ütközéseket. Procedurálisan is érdemes használni őket, szintén a név ütközések elkerülése végett.
  • A függvényeknél a procedurális kód esetén szintén lehetnek név ütközések. Ezeket ugyanúgy, mint a fájloknál prefix-ekkel szokták feloldani, pl: mysql_real_escape_string(). Az oo kódnál nincs szükség ilyesmire, mert két eltérő osztályban lehetnek teljesen azonos nevű függvények, pl: mysqli::escape() és mysql::escape(). Procedurálisan névterekkel feloldható ez a probléma: \mysql\real_escape(). Ha sok különböző implementációja van az escape-nek, akkor mindegyiknek külön névteret kell létrehozni procedurális megközelítésnél. Ezzel szemben objektum-orientált megközelítésnél új osztályt kell létrehozni mindegyikhez. Szóval a névterek ilyen szempontból elég hasonlóak az osztályokhoz.
  • Az osztályok a névtereknél valamivel többet nyújtanak. Lehet megadni nekik közös interface-t. Ez azt jelenti, hogy azonos nevű metódusok (procedurálisnál függvények) kell, hogy legyenek bennük. Ha ez nem teljesül, akkor hibát dob a rendszer. Ez a kikényszerítés azért jó, mert így az osztályok felcserélhetővé válnak. Pl van egy osztályod, ami adatbázisban tárol dolgokat, van egy, ami memóriában, és van egy, ami fájlrendszerben. Amíg ugyanazt az interface-t implementálja mindhárom, addig kiválthatóak egymásban. Minket általában csak az szokott érdekelni egy tároló használatakor, hogy letárolja az adatot, amit adunk neki, és nem az, hogy mindezt hogyan csinálja. Procedurális kódnál nem lehet kikényszeríteni ilyen interface-t, csak meg lehet próbálni használni, és ha nincs olyan nevű függvény a névtérben, amilyet használni akarunk, akkor jelezni fogja a rendszer. Azt már nem fogja írni, hogy mivel kapcsolatban keresi azt a függvényt, azt majd nekünk kell kitalálni a debuggolásnál. Az oo kód esetében viszont írni fogja az interface nevét, így tudni fogjuk egyből, hogy mit hagytunk ki. Az osztályoknál van még olyan extra funkció, hogy örököltetés. Ezzel egy szülő osztályról tovább lehet örököltetni egy gyerek osztályra bizonyos metódusokat. A procedurális megközelítésnél ez kiváltható azzal, hogy az egyik névtérből meghívjuk egy másik névtérben levő függvényeket. Ez sok helyen kód duplikációhoz vezethet.


Összességében az oo megközelítés nyelvi szinten valamivel fejlettebb eszközöket nyújt, mint a procedurális. Az, hogy mekkora a különbség a procedurális szemlélettel elérhető eszközök között és az oo szemlélettel elérhető eszközök között, már teljesen nyelv függő. A magas szintű nyelvek esetében kicsit, vagy jobban, de az oo felé szokott billenni a mérleg, ha az elérhető eszközök minőségét nézzük. Az alacsony szintű nyelvek esetében csak a procedurális megközelítés használható, úgyhogy ott nincs miről beszélnünk. A magas szintű nyelvek esetében ez a viszonylag kis különbség az elérhető eszközökkel kapcsolatban elég volt ahhoz, hogy a hozzáértő emberek nagy többsége áttérjen az objektum orientált programozásra. A kevésbé hozzáértők nem feltétlen gondolták végig, hogy ez miért jó nekik, de mivel a profik azt mondták, hogy ez a jó, ezért divatból ők is áttértek. Gondolom ez az egész oo - procedurális vita abból adódik, hogy sokan csak divatból használják az oo-t, nem értenek igazán a benne elérhető eszközökhöz, és megfogalmazni sem tudják, hogy miért jobb az oo eszközök használata, mint a procedurális eszközöké. Nyilván aki a procedurális programozást magas szinten űzi, az képes egy jobb minőségű kód előállítására, mint aki az oo programozást alacsony szinten űzi, így érv mindig lesz a procedurális mellett, az oo-val szemben, ha ezek a felek vitatkoznak a témáról...

off:
Én nem szeretnék többet hozzászólni a témához, ez a végleges véleményem, eléggé átgondoltam az elmúlt napokban, és ezzel kapcsolatban a további vita szerintem szőrszálhasogatás, amire meg nincs se kedvem, se időm...
48

@Szita Szilárd: Én azt tudom

inf · 2013. Okt. 20. (V), 16.03
@Szita Szilárd:

Én azt tudom javasolni, hogy nem az oo-t kezdd el megtanulni, hanem olvasd végig ezt a hozzászólást, és értsd meg, hogy mit miért csináltam, amikor átrendeztem a kódot, kiemeltem külön függvényekbe, stb... Amikor oo-ban programozik az ember, akkor is nagyjából ugyanígy szétválasztja a kódot témakörök szerint, külön osztályokba, névterekbe, stb... rendezi. Szóval pusztán attól, hogy ismered az oo eszközöket nem leszel jobb programozó. Attól leszel jobb programozó, ha megtanulod úgy rendszerezni a kódodat, hogy az másnak is érthető legyen. Az szinte lényegtelen, hogy mindezt oo-ban csinálod e, vagy procedurálisan. Az oo valamivel több eszközt nyújt erre, de ha nem tudod megfelelően használni ezeket az eszközöket, akkor teljesen mindegy, hogy procedurálisan, vagy oo-ban írod a kódodat, ugyanolyan nehezen érthető, nehezen módosítható, rossz minőségű kód lesz. Ha valami nem világos, akkor inkább kérdezz!
49

Nagyon jól összeszedted a

Hidvégi Gábor · 2013. Okt. 20. (V), 16.35
Nagyon jól összeszedted a dolgokat, és objektív összefoglalót adtál.
51

Alapból tetszik

Pepita · 2013. Okt. 21. (H), 01.15
Nagyon jól összeraktad, az viszont kérdéses számomra, hogy neki ez így mennyire jó. Olyan értelemben, hogy nagyon jól összeszedted tényleg (vagy inkább szét), de egyetlen kommentben, bár több lépésben, lehet, hogy ez egyszerre sok neki.
Valamint nem ő csinálta, hanem te.
Kíváncsi vagyok, hogy mit hoz ki Szilárdból, én vele csináltattam volna, több idő alatt. De ha ezt ugyanolyan jól "magáévá teszi", akkor rengeteg időt-energiát spóroltál neki.
50

Remek összefoglaló. Le a

bamegakapa · 2013. Okt. 20. (V), 20.27
Remek összefoglaló. Le a kalappal.
67

WebService-eknél érdekes,

inf · 2013. Okt. 22. (K), 14.48
WebService-eknél érdekes, hogy a ROA(REST) analóg az objektum orientált megközelítéssel, a SOA(SOAP) meg analóg a procedurális megközelítéssel. Az egyik erőforrásokat (objektumokat) publikál, a másik meg műveleteket (függvényeket)...

Megintcsak érdekes, hogy mennyi köze van ennek az analógiának ahhoz, hogy REST fölé lehet öngeneráló klienst írni, míg SOAP fölé nem lehet. Kellene hozzá egy külön leíró, ami összeköti egymással a service-eket...
75

Írni fogok egy cikket

inf · 2013. Okt. 23. (Sze), 03.42
Írni fogok egy cikket kezdőknek programozási elvekről. Ez nem most lesz, mert még a biztonsági cikkekre sincs időm, nem hogy erre, de valamikor a télen sort kerítek rá.
140

Imho emeljük ki az oo

inf · 2013. Okt. 25. (P), 15.41
Imho emeljük ki az oo elméletes témát ebből, mert már túl nagy a mélysége a fának :D
142

Új témába gondolod? Indíts

Joó Ádám · 2013. Okt. 25. (P), 15.59
Új témába gondolod? Indíts egyet, kiemelni egy fát egyelőre nem lehet, bár gyakran hasznos volna.
143

Indítani fogok egyet, valami

inf · 2013. Okt. 25. (P), 16.30
Indítani fogok egyet, valami olyat, amiben nem lesznek ilyen kifejezések, hogy encapsulation, polymorphism, stb..., hanem csak egy gráf betűkkel, meg példák arra, hogy melyik betű mit jelent. Aztán majd szótárazunk...

Fájl vagy képet hogyan lehet beszúrni?
144

Az [img] taggel. De gráfot

Joó Ádám · 2013. Okt. 25. (P), 17.39
Az [img] taggel. De gráfot tudsz rajzolni a kódszínezővel is.
145

Hogyan?

inf · 2013. Okt. 25. (P), 18.40
Hogyan?
146

ASCII :)

Joó Ádám · 2013. Okt. 25. (P), 18.46
ASCII :)
147

á az nem az igazi, max fánál

inf · 2013. Okt. 25. (P), 22.59
á az nem az igazi, max fánál jó

hogyhogy nincs képfeltöltés?

a kódot még érteném, hogy nem akarsz vírust nyomatni, de képet...
148

Nem én fejlesztettem a

Joó Ádám · 2013. Okt. 25. (P), 23.29
Nem én fejlesztettem a rendszert :)
149

nem tudsz belenyúlni, vagy

inf · 2013. Okt. 26. (Szo), 02.09
nem tudsz belenyúlni, vagy nem akarsz?

jó lenne, ha lehetne képet, kódot, yed gráfot, psd-t, stb... mellékelni
150

Úgy döntöttem, hogy svg-ben

inf · 2013. Okt. 26. (Szo), 17.34
Úgy döntöttem, hogy svg-ben csinálom a gráfot, aztán bárki megnézheti, módosíthatja, ha akarja, és el lehet küldeni kód formájában...
151

Ne haragudj, de

Pepita · 2013. Okt. 27. (V), 00.34
Drupalban ez kb. 3 kattintás, hogy képet mellékelhess. Gondolom van admin jogod. :)