Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.

OOP - principi programiranja

[es] :: PHP :: OOP - principi programiranja

Strane: 1 2

[ Pregleda: 9107 | Odgovora: 34 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

krksi
PHP Developer
Beograd

Član broj: 281484
Poruke: 22
95.180.40.*



Profil

icon OOP - principi programiranja12.03.2011. u 15:08 - pre 159 meseci
Poz svima.
Malo sam cesljao po ES i naisao na jednu jako zanimljivu temu. Tema je http://www.elitesecurity.org/t396391-0#2569591
Mislim na OOP pristup koji se razmatrao tu i na vojnike i ciscenje lisca:

Citat:
mitke013: OOP nije gomilanje funkcija na jedno mesto pa se to mesto nazove klasom. Objekat moze nesto da uradi, a ne samo da drzi funkcije; za tako nesto moze se koristiti i include fajla koji ce ih drzati.

Najjednostavnije objasnjenje:
tvoj program je komandir kasarne. Imas klasu vojnik, zastavnik, kapetan....

Tebi kapetan treba da organizuje jedan od visoko-intelektualnih zahteva tipicnih za vojsku; ciscenje piste, skupljanje lisca ili nesto slicno.

Code:

$captain = Captain::getAvailable() ;

Nema parametara. Klasa ce naci slobodnog kapetana tj. onaj koji je trenutno tu i nema zaduzenja.

Code:

$captain->cleanEverything() ;


Opet nema parametara. Kapetan ce dalje da organizuje taj posao. On ce naci slobodne vojnike na slican nacin i podeliti naredjenja. Pritom:
Code:

$soldier_1->cleanLeaves() ;
$soldier_2->cleanRanaway() ;
//itd

Vojniku treba metla; moglo je znaci i ovako:
Code:

$broom = Broom::getAvailable() ;
$soldier_1->cleanLeaves($broom) ;

Ali sto bi kapetan vojniku davao metlu; nije debil, moze i sam da je nadje. Pritom, ako jednog dana se kasarna modernizuje i dobije onaj kompresor sto oduva lisce, komanda vise nije validna. Ako se vratimo u programske vode, to znaci da bi svuda gde kapetan daje vojniku metlu ili nesto drugo, moralo da se promeni. Lakse je nauciti vojnika da se sam snadje:
Code:

class Soldier extends BasicMilitaryUnit
{
  public function cleanLeaves()
  {
    $cleaningDevice = $this->getCleaningDevice() ;
    // ocisti lisce koristeci $cleaningDevice 
  }

  protected function getCleaningDevice()
  {
    return Broom::getAvailable() ;
  }
}

Static metode je uvek lakse prepraviti nego dinamicke. Uvek ih je manje, a ako je protected, automatski znas da se ta metoda ne poziva ni sa jednog drugog mesta i da ne treba da juris kroz ceo program da proveris pozive.

Sve ove klase nasledjuju BasicMilitaryUnit klasu jer je za svo vojnicko osoblje identicno da treba da jedu, srede ujutru, obuju se, izadju na smotru itd. Da ne bi to isto pisali za svakog, lakse je staviti na jedno mesto.

Jos jedan primer nasledjivanja; u vojsci se belezi skoro svaki obavljeni posao. Posto to programer zna od pocetka, u svakoj metodi koja zahteva izvestaj na kraju ce pozvati:
Code:
  public function cleanLeaves()
  {
    $cleaningDevice = $this->getCleaningDevice() ;
    // ocisti lisce koristeci $cleaningDevice 

    $this->writeReport('Ocistio sam lisce') ;
  }

a BasicMilitaryUnit ima metodu:
Code:

abstract class BasicMilitaryUnit 
{
  protected function writeReport($report)
  {
    $name = $this->getName() ;
    $rank = $this->getRank() ;
   // snimi izvestaj koristeci tekst raporta, za ime i cin se metoda sama snasla
  }
}

OK? Nije; na ovaj nacin klasa vojnik prosledjuje fixni tekst. Ako se taj tekst negde snima (baza) i jednog dana tekst promeni, baza ce imati razlicite tekstualne vrednosti za isti posao. Bolje je:
Code:
  public function cleanLeaves()
  {
    $cleaningDevice = $this->getCleaningDevice() ;
    // ocisti lisce koristeci $cleaningDevice 

    $this->writeReport(Report::LEAVES_CLEANED) ;
  }


Sad se koristi konstanta iz klase Report. Neka je vrednost const LEAVES_CLEANED = 1 ; Mi ce tu vrednost da snimimo u bazu; na osnovu tog broja se tekst raporta moze menjati bez problema, lokalizovati itd.

Koliki posao oko obicnog lisca :)



[Ovu poruku je menjao mitke013 dana 08.04.2010. u 16:58 GMT+1]

[Ovu poruku je menjao mitke013 dana 08.04.2010. u 17:16 GMT+1]



Pozz i za Mitketa, pratio sam i druge teme i video da forsira Doctrine ORM :)
Lm, zelim da iznesem svoj stav o tome kako bi trebao da izgelda OOP pristup. Sa Mitketom se slazem do nekle, ali ne u potpunosti (mislim na komandira i ciscenje kasarne). Slazem sa u delu gde klasa treba sama da se snadje, i da sto manje parametara metoda prima, to je i bolje, lakse se kod odrzava, preglednije je itd. (mada ne smatram da je i los OOP ako ima i neki parametar naravno, sve zavisi od situacije i potrebe). Ono sto mi u ovom pristupu trenutno strci to je klasa Soldier i metoda getCleaningDevice():

Code:

class Soldier extends BasicMilitaryUnit
{
  public function cleanLeaves()
  {
    $cleaningDevice = $this->getCleaningDevice() ;
    // ocisti lisce koristeci $cleaningDevice 
  }

  protected function getCleaningDevice()
  {
    return Broom::getAvailable() ;
  }
}


jer mislim da su ovime naruseni neki pricnipi u OOP-u. Prvi prinicip koga se treba pridrzavati je da se konkrente klase sto manje poznaju, tj. da sto manje znaju jedna za drugi, ili da nisu svesne jedna druge. To bi znacilo da treba izbegavati direktno vezivanje konkretnih klasa jer je odrzavanje znatno teze. U ovom primeru, klasa Soldier zna za klasu Broom, i mislim da je to velika greska. Samim tim i veza je kruta izmedju ove klase i teze ce se refaktorisati kad bude bilo potrebe. Recimo, sta se desava ukoliko vojska izbaci metlu iz upotebe i krene sa usisivacima ? Da bi se to reimplementiralo, potrebno je izmeniti metodu getCleaningDevice() tako da ne vraca metlu vec usisivac. To je drugi naruseni princip ili poznatiji kao OCP (open close principe). To znaci da klase ne bi trebalo da se menjaju i da sto je jednom kreirano, ostane tako kako jeste, sto ovde nije slucaj. Trece sto je naruseno, a to je da klasa Soldier instancira u sebi metlu. Pored toga sto klasa Soldier cisti lisce ili kasarnu, ona je odgovorna i za kreiranje metle. Time je narusen princip SRP (single responsability principe), sto znaci da bi svaka klasa trebala da ima jednu odgovornost (u ovom slucaju, ona ima dve- da cisti i kreira metlu).

Da bi ovo izbegli, ja bi to resio na ovaj nacin:

Code:

class Soldier {
    private $tool;
    
    public function setTool(Tool $tool) {
        $this->tool = $tool;
    }
    public function cleanLeaves() {
        $this->tool->clean();
    }
}

interface Tool {
    function clean();
}

class Broom implements Tool {
    function clean() {
        echo "Cistim uz pomoc metle";
    }
}


Prilikom pokretanja koda, potrebno je samo da se inicijalizuju objekti i pravilno povezu :

Code:


class Main {
    
    public function main() {
        $soldier = new Soldier();
        $soldier->setTool(new Broom());
        $soldier->cleanLeaves();
    }
}


Mislim da smo ovako resili probleme i da vise ne moramo da modifikujemo ni klasu Soldier ni Broom. Ukoliko se izbaci metla iz upotrebe i uvede usisivac, jednostvano se doda nova klasa:

Code:

class VacuumCleaner implements Tool{
    function clean(){
        echo "Cistim uz pomoc usisivaca";
    }
}

i u init delu, ili u nasem primeru Main, treba samo izmeniti :

Code:
$soldier->setTool(new Broom());


u

Code:
$soldier->setTool(new VacuumCleaner());


Tako da nase klase se uopste ne menjaju, a sto je najvaznije, te konkretne klase i ne znaju jedna za drugu. Metla nije svesna postojanja usisivaca, a oni pak nisu svesni ni postojanja vojnika, kao ni vojnik njih. Tako da prilikom sledeceg refaktorisanja, mogucnost greske je drasticno smanjena.

Eto, to je moje vidjenjen OOP-a :)
OOP bez koriscenja paterna je nista drugo nego malo lepse proceduralno programiranje.

[Ovu poruku je menjao krksi dana 13.03.2011. u 09:34 GMT+1]
 
Odgovor na temu

mitke013
As Divljine
Freelancer

Član broj: 231934
Poruke: 338
*.dynamic.isp.telekom.rs.



+34 Profil

icon Re: OOP - principi programiranja12.03.2011. u 18:17 - pre 159 meseci
Poz krksi.

Prvo, drago mi je sto uopste i razmisljas o mom ponudjenom resenju. Vise puta sam naglasio da nikad ne treba verovati necemu sto se procita, pa ni onome sto ja napisem. "Think, don't follow"

Drugo:
ne slazem se kako si uradio primere. Evo ti i zasto:
ti forsiras (cini mi se) SOLID princip, tj. da se objekti medjusobno 'ne poznaju'. To moze proci kod manjih programa gde sve jos i mozes da drzis u glavi. Npr. tvoj kontrolor ima logiku setTool (new Broom()). Znam da je ovo veoma, veoma sitno i nebitno, ali je opet logika i u kontroloru je. I dobijas jos jednu public metodu i moras da napises bar jos 2 testa minimum. Zasto, kad tebe samo zanima da posao bude uradjen?

Ali veci problem je ako ti ovu metodu pozivas sa 30 mesta. Kod velikih programa je potpuno normalna stvar da se 'neka' metoda iznova i iznova koristi. Sta ces onda?

Veliki programi su kao automobil; svaka komponenta je nekako vezana sa drugom. Ako ode objekat akumulator, nece ti vise raditi objekti far i podizaci stakala (ok, nece ceo auto, ali ovo je samo ideja). Ali radice ti objekat brava. Ako ti iscuri objekat ulje, nece ti raditi rucna i nozna kocnica. Kod nekih automobila, nece ni objekat motor jer ce ga onboard kompjuter zaustaviti.

Tvoj primer, kad se izbaci metla i ubaci usisivac, je suvise jednostavan. Evo ti nesto teze, real-life situacija, o cemu se mnogo trolova.... raspravljalo na nekoj temi. Problem je sledeci:

Imas klasu Song. Ona ima timestamp kolonu 'created_at', sto znaci da je datum npr. 2010-03-12 18:30:11 . Ti imas foreach petlju u nekom template-u koji prikazuje poslednjih 30 pesama. Znaci u petlji bi uradio

Code (php):

{foreach ..... $song}
...
$song->getCreatedAt()
...
{/foreach}
 


I dobro, ovo ce da radi, pored svake pesme dobices defaultni timestamp format.

Ali recimo, klijent hoce format 12. Mart 2010. Kako bi ti izmenio taj format? Po tvom objasnjenju da slanje parametara nije lose, zakljucio sam da bi uradio sledece:
Code (php):

{foreach ..... $song}
...
$song->getCreatedAt('d.M Y')
...
{/foreach}
 


Mana:
ako imas veliki program, moras da izmenis desetine template-a.

Ja to resavam ovako:
Code (php):

          /**
          * Returns friendly looking date of created_at column
          *
          * @return string
          */

          public function getCreatedAt()
          {    
               $date = new DateTime($this->created_at);
               return $date->format(Settings::getInstance()->getDateFormat()) ;
          }
 

Vidis razliku? Ja sam izmenio samo jednu metodu umesto ko zna koliko .tpl fajlova.

Ali, ajde da jos malo zamutim: na ovoj temi sam predstavio najbolji program koji sam ikada napravio. I najponosniji sam na 100% visejezicku podrsku. Ako odes na hhttp://www.youmicro.com/listen...alien-ant-farm-smooth-criminal , videces datum u formatu 'Mar 09, 2011'. Prebaci na spanski jezik; datum kreiranja ce biti: '09 Mar 2011'.

Kod za to je:
Code (php):

          public function getCreatedAt()
          {    
               $date = new DateTime($this->created_at);
               return $date->format(Translation::getForVisitor()->date_format) ;
          }
 


Ovo je prava, real-life situacija. Kod je na pocetku zaista bio kao u gornjem primeru, ali sam ja predlozio da se i datumi mogu podesiti prema vec odabranom jeziku. Koliko mi trebalo? 1 minut za metodu, 1 minut za novu kolonu u tabeli 'translation' i 1 minut za 'date format' kolonu u template-u. Pogledaj ovu sliku, videces i sam. 'd. M Y.' je defaultna opcija koju admin menja iz interfejsa.

Zasto ti ovo navodim? Pa ove real-life situacije krse tvoja pravila da se objekti 'ne poznaju'. U prvom slucaju, Song poznaju klasu Settings. U drugom slucaju, Song poznaje klasu Translation. To je sve logika i logika ide u model, NE u kontroler.

Btw; prica se tu ne zavrsava: Translation::getForVisitor() takodje krsi tvoja pravila. Ona prvo pita User::isLogged() . Ako je korisnik ulogovan, vratice translation koji je on odabrao. Ako nije ulogovan, pogledace cookije; to mozes da vidis kad promenis jezik na sajtu. Ako ni cookie ne nadje, vraca defaultni jezik, u ovom slucaju engleski.

Nigde parametara, kod je jako kratak a funkcionalnost kakvu nisam video ni u jednom drugom programu.

Citat:

OOP bez koriscenja paterna je nista drugo nego malo lepse proceduralno programiranje.


Slazem se u potpunosti. Zato ja koristim active-record pattern. Ali ideja da se objekti ne poznaju zove se SOLID pattern i to ja zovem 'grupisanje funkcija u klasu'. Sem autoload-a i price kako je to OOP (sto i jeste po definiciji), nista drugo nisi dobio. I dalje ces imati logiku u kontroloru i daleko kompleksniji kod nego ovo sto ja radim.

Javi sta mislis o svemu ovome. Pazi, uopste ne mora da znaci da je ovo moje resenje zaista i najbolje resenje, ali sam kroz praksu na vecim programima dosao do toga. Ja ne radim blogove i prezentacije pa da mogu da drzim sve u glavi; meni je bitno da model uradi nesto sto mu kaze drugi model; test je tu da vidi da li je stvar i uradjena i briga ga kako je to uradio.

[Ovu poruku je menjao mitke013 dana 12.03.2011. u 19:29 GMT+1]
 
Odgovor na temu

mitke013
As Divljine
Freelancer

Član broj: 231934
Poruke: 338
*.dynamic.isp.telekom.rs.



+34 Profil

icon Re: OOP - principi programiranja12.03.2011. u 18:28 - pre 159 meseci
Zaboravio sam jedno:
Citat:
To znaci da klase ne bi trebalo da se menjaju i da sto je jednom kreirano, ostane tako kako jeste, sto ovde nije slucaj


Ovo je veoma lose razmisljanje. Ti prakticno 'zakucavas' kod umesto da mu omogucis da 'zivi' i da se lako prosiruje. Sta ces kad se program upgrade-uje? Dodavati iznova i iznove nove klase i nove metode? Posle nekog vremena imaces gomilu obsolete stvari. Na kraju bi se sve to svelo na ponovno pisanje celog programa jer je lakse to nego snaci se sta je sta, sta se koristi a sta ne itd... Vrlo, vrlo losa ideja. Probaj da razumes; program je ziv i on treba da se menja. Zato mene moji klijenti veoma cene i trpe sva moja izivljavanja; dovoljno je da uporede moj kod sa onim sto drugi rade.

Ako ti treba jos primera, drage volje cu ti pokazati. Ja ne krijem puno i zaista mi drago sto kriticki razmisljas.
 
Odgovor na temu

krksi
PHP Developer
Beograd

Član broj: 281484
Poruke: 22
95.180.40.*



Profil

icon Re: OOP - principi programiranja12.03.2011. u 19:29 - pre 159 meseci
ok, evo moje replike :)

Citat:
ne slazem se kako si uradio primere. Evo ti i zasto:
ti forsiras (cini mi se) SOLID princip, tj. da se objekti medjusobno 'ne poznaju'. To moze proci kod manjih programa gde sve jos i mozes da drzis u glavi. Npr. tvoj kontrolor ima logiku setTool (new Broom()). Znam da je ovo veoma, veoma sitno i nebitno, ali je opet logika i u kontroloru je. I dobijas jos jednu public metodu i moras da napises bar jos 2 testa minimum. Zasto, kad tebe samo zanima da posao bude uradjen?

Ali veci problem je ako ti ovu metodu pozivas sa 30 mesta. Kod velikih programa je potpuno normalna stvar da se 'neka' metoda iznova i iznova koristi. Sta ces onda?


ovo je samo najobicniji primer bio. Ne mora da se kreira to u kontorloru, na kraju krajeva i ne treba. Potrebna je neka klasa koja bi predstavljala kreator klasu i sve bu se tu kreiralo. Kontrolor bi onda samo pozivao te klase i spajao sta treba.

Citat:
Veliki programi su kao automobil; svaka komponenta je nekako vezana sa drugom. Ako ode objekat akumulator, nece ti vise raditi objekti far i podizaci stakala (ok, nece ceo auto, ali ovo je samo ideja). Ali radice ti objekat brava. Ako ti iscuri objekat ulje, nece ti raditi rucna i nozna kocnica. Kod nekih automobila, nece ni objekat motor jer ce ga onboard kompjuter zaustaviti.


To si upravu, ako crkne akumulator, nece raditi, recimo brisaci. To i nije sporno, tako i ako vojnik nema metlu, nece cistiti. Nego pitanje je da li je akumulator svestan brisaca ? Odgovor: naravno da nije. Njegovo je da samo proizvodi struju, a ko ce je koristiti, to nije njegov posao, niti on treba da zna. Obratno, da li su brisaci "svesni" akumulatora? Odgovor: naravno da nisu. Oni jedino znaju da moraju da prime struju od nekog da bi radili, a ko ce to da bude, to njih nije briga. Pimera radi, zelis da na automobilu iskljucis napajanje za brisace i zelis da nemaju dotok struje. To sigurno neces uraditi tako sto ces otvoriti akumulator i nesto u njemu menjati, vec samo zicice ces prekinuti, tj. vezu (zato sto akumulator ne zna za brisace i u njemu nema niceg vezano za iste). E sad, zamisli da je akumulator svestan brisaca i da je u samom akumulatoru ugradjen deo koji upravlja briscima. Onda ces morati da otvoris akumulator i da nesto "prckas" po njemu kako bi iskljucio brisace. Ali pri tom muvanju mozes da izbrkas nesto i da pokvraris rad, recimo radio kasetofona. Pa u nameri da popravis radio kasetofon, mozes da pokvaris svetla za maglu itd. Zato mislim da je bolje da se klase ne poznaju.

Sto se tice one pesme, ja ne bih naravno ubacio onaj parametar kao sto si mislio da bi uradio, nego bi uradio ovako:

Code:

class Song {

    private $settings;

    public function setSettings(ISettingsFormatDate $stt) {
        $this->settings = $stt;
    }
    public function getCreatedAt() {
        $date = new DateTime($this->created_at);
        return $date->format($this->settings->getDateFormat()) ;
    }
}

interface ISettingsFormatDate {
    function getDateFormat();
}

class MyFormatDate implements ISettingsFormatDate {
    public function getDateFormat() {
        return "d.M.Y.";
    }
}


Ovde sam samo obracao paznju na format datuma, cak mislim da ni datum ne bi trebao tu da bude, ali ok, da ne komplikujemo. Recimo, sta bi uradio ako u apalikaciji treba da pozoves metodu getCreatedAt() klase Song, ali treba da je pozoves na 10ak razlicitih mesta i da imas na svakom mestu razlicit nacin formatiranja ? To bi morao nekako da resis dinamicki, pa me zanima tvoja ideja kako bi to moglo da se uradi, naravno na osnovu tvog primera.

p.s.
Ja sam se naravno susretao sa ovim problemima kroz praksu, i ovako sam ih resavao: posto koristim smarty kao template engine, ja tpl strani prosledim timestamp, znaci vrednost u sekundama, pa nakon toga, na strani formatiram datum: {$datum|date_format:"%d.%M.%Y."} i tako zaobilazim dodatno kodiranje u php-u (tj. formatira dizajner kako bu bude nalozeno, to vec i nije moj posao).

Citat:
Ovo je veoma lose razmisljanje. Ti prakticno 'zakucavas' kod umesto da mu omogucis da 'zivi' i da se lako prosiruje.


Tacno, upravo o tome i diskutujemo. Kod (klasa) treba lako da se prosiruje, ali ne i da se menja. Svaka izmena postojeceg koda je mogucnost greske na onom mestu gde se taj kod koristi. Kod ne zakucavam, vec zatvaram za modifikaciju, a aplikacija zivi tako sto se prosiruje novim klasama i funkcionalnostima.

Citat:
Sta ces kad se program upgrade-uje? Dodavati iznova i iznove nove klase i nove metode?


Da, naravno. Kada se dodaju nove klase, ti rad i sigurnost aplikacije nikako ne mozes da dovedes u pitanje, ali ako menjas kod, mozes i tekako. Radio sam na vecim projektima i ovo pricam iz iskustva. Cak zbog lose organizovanosti i zavisnosti klasa morao sam da projektujem iz pocetka kako bi ispostovao nove zahteve korisnika. Uvek se trudim da primenjujem paterne koji mi olaksavaju zivot. Tacno je da se broj klasa drasticno povecava, ali zato kasnije mnogo manje imas problema sa izmenama.

To je moje misljenje, tako radim i lepo se snalazim. Medjutim, samo glup covek misli da sve zna, pa zato jednostavno volim i da cujem i druga misljenja, da vidim kako drugi rade, jer u svakoj diskusiji se nauci i nesto novo, tako se i u savrsavam, jer kao sto rekoh, ne bi da ispadnem glup i da mislim da sve znam :)

p.s.
bacio sam pogled samo na slike ovog tvog projekta, nisam detaljnije pogledao pa ne bih komentarisao. Kad budem bolje pogledao, onda cemo diskutovati :)
 
Odgovor na temu

mitke013
As Divljine
Freelancer

Član broj: 231934
Poruke: 338
*.dynamic.isp.telekom.rs.



+34 Profil

icon Re: OOP - principi programiranja12.03.2011. u 20:28 - pre 159 meseci
Evo kratak osvrt, ne mogu sad na sve da odgovorim. Greska ti je ovde:

Code (php):

    public function getCreatedAt() {
        $date = new DateTime($this->created_at);
        return $date->format($this->settings->getDateFormat()) ;
 


Ti format datuma definises zakucano u klasi Song. Ja omogucavam adminu da sam bira format datuma, pogledaj sliku opet. Mislim da si bespotrebno zakomplikao kod.

Citat:
Recimo, sta bi uradio ako u apalikaciji treba da pozoves metodu getCreatedAt() klase Song, ali treba da je pozoves na 10ak razlicitih mesta i da imas na svakom mestu razlicit nacin formatiranja ?

Ovo se nikad nece desiti, probaj samo da zamislis takvu situaciju. Meni treba ILI timestamp format koji procitam $song->created_at , ILI friendly format $song->getCreatedAt(). Da, tacno je da bi se ova metoda trebala zvati getFriendlyCreatedAt() ili slicno, ali volim da mi .tpl bude citak. Moj PhpEd jos nema code-completition za objekte u .tpl fajlu

Drugo: koji je realan scenario da bi se ovo formatiranje koristilo IGDE osim u .tpl fajlu? Zasto bi Album koristion tu metodu? Ako mu bas treba created_at kolona, procitace timestamp vrednost, njemu preformatiran format ama bas NISTA ne znaci. Nadam se da me razumes; ovo su sve real-life situacije.

Citat:
Ja sam se naravno susretao sa ovim problemima kroz praksu, i ovako sam ih resavao: posto koristim smarty kao template engine, ja tpl strani prosledim timestamp, znaci vrednost u sekundama, pa nakon toga, na strani formatiram datum: {$datum|date_format:"%d.%M.%Y."} i tako zaobilazim dodatno kodiranje u php-u (tj. formatira dizajner kako bu bude nalozeno, to vec i nije moj posao).


Primer nije bio za $datum, vec za $song koja ima kolonu created_at. Rec je o prikazu niza objekata iz baze, ne o nekog promenljivoj.

Citat:
To si upravu, ako crkne akumulator, nece raditi, recimo brisaci. To i nije sporno, tako i ako vojnik nema metlu, nece cistiti. Nego pitanje je da li je akumulator svestan brisaca ? Odgovor: naravno da nije.


Ovo ti je isto: Vojnik je svestan metle, ali metla nije svesna vojnika. Isto kao sto je brisac svestan akumulatora, ali akumulator nije svestan brisaca. Tvoj primer je isti kao moj

Citat:
Da, naravno. Kada se dodaju nove klase, ti rad i sigurnost aplikacije nikako ne mozes da dovedes u pitanje, ali ako menjas kod, mozes i tekako. Radio sam na vecim projektima i ovo pricam iz iskustva. Cak zbog lose organizovanosti i zavisnosti klasa morao sam da projektujem iz pocetka kako bi ispostovao nove zahteve korisnika. Uvek se trudim da primenjujem paterne koji mi olaksavaju zivot. Tacno je da se broj klasa drasticno povecava, ali zato kasnije mnogo manje imas problema sa izmenama.


Ne mozes. Zato ti sluze unit-testovi koji su obavezni kod svakog ozbiljnog programa, narocito kod onih gde ocekujes future upgrade i/ili rade sa parama.

Najlakse je zatrpavati program novih klasama, novim metodama, trpaj, guraj... Dok ne stignes do tacke da vise ne znas cemu sta sluzi. Ja to zaista necu da radim.

Unit testovi ti mnogo skracuju program jer te skoro teraju da ne stavljas logiku u kontroler. Na kraju dobijes kontrolere od nista koda i program koji se jako lako upgrade-uje. Moras da probas TTD da bi razumeo sta ti kazem, ovako je tesko.

Hint:
Svidja mi se sto stavljas primere koda, ali dodaj molim te :php u ono [ code]. Bice lepse formatirano



 
Odgovor na temu

krksi
PHP Developer
Beograd

Član broj: 281484
Poruke: 22
95.180.40.*



Profil

icon Re: OOP - principi programiranja12.03.2011. u 21:05 - pre 159 meseci
Citat:
Ti format datuma definises zakucano u klasi Song. Ja omogucavam adminu da sam bira format datuma, pogledaj sliku opet. Mislim da si bespotrebno zakomplikao kod.


Da, to i ne treba tako, to sam i naglasio :
Citat:
Ovde sam samo obracao paznju na format datuma, cak mislim da ni datum ne bi trebao tu da bude, ali ok, da ne komplikujemo.


Naravno da datum formatiranja nema nikakve veze sa pesmom, pa je zato i na losem mestu, ali to sam uzeo samo kao primer.

Citat:
Ovo se nikad nece desiti, probaj samo da zamislis takvu situaciju.

Ma nema ja sta da zamisljam, kako bi ti to resio ? :)
Recimo, radim u firmi koja nema veze sa IT poslovima. Meni je sef nalozio na nadjem nekog programera koji ce napraviti neku web aplikaciju u php-u za potrebe firme. E sad, kako se ja i sef ne "mirisemo" najbolje i ne podnosimo, ja sam resio malo da mu napakostim. Moze mi se jer igrom slucaja, radim jos 10ak dana i prelazim u drugu firmu. I ja nadjem tebe kao programera da napravis to, i zelim da uvek kada se prikaze datum, da se prikaze ralicit format. Eto, vidis da moze da se desi :)


Citat:
Primer nije bio za $datum, vec za $song koja ima kolonu created_at. Rec je o prikazu niza objekata iz baze, ne o nekog promenljivoj.


jeste za song, a valjda je bilo reci o prikazu datuma, tj. timestampa za svaku pesmu? :

Code (php):

{foreach ..... $song}
...
$song->getCreatedAt()
...
{/foreach}
 


Citat:
Ovo ti je isto: Vojnik je svestan metle, ali metla nije svesna vojnika. Isto kao sto je brisac svestan akumulatora, ali akumulator nije svestan brisaca. Tvoj primer je isti kao moj


Pa ja ipak mislim da ni vojnik nije svestan metle kao ni brisaci akumulatora. Vojnik je samo svestan da odredjenim alatom treba da ocisti kasarnu, a da li je to metla, usisivac ili nesto trece, to je manje bitno, vazno je da taj alat ima mogucnost ciscenja. Sto se brisaca tice, oni nikako nisu svesni akumulatora, oni su samo svesni da treba da dobiju struju od nekog, a taj neko ne mora da bude akumulator. Oni mogu da je dobiju i direktno sa trafo stanice, samo da se pre toga jacina struje prilagodi adapderom :)
Tako da je brisace bas briga od koga dobijaju struju, za njih je bitno da je dobijaju.

p.s
hvala za savet za :php u kodu :)

 
Odgovor na temu

_korso_

Član broj: 82797
Poruke: 163
*.adsl-a-4.sezampro.rs.



+1 Profil

icon Re: OOP - principi programiranja12.03.2011. u 23:23 - pre 159 meseci
Bacih pogled na ovu temu veceras, pa bih hteo samo da prokomentarisem par stvari. Nadam se da ce biti konstruktivno.
Primer za Song u http://www.elitesecurity.org/t424766-0#2831118.

Da ne ulazimo u detalje Settings i Song klase, da li druga treba da zavisi od prve i sl.
Ali ako je postavka vec ovakva i ove dve klase funkcionisu na ovaj nacin ...

1. Primer teoretski zapravo jeste jako dobar.
Song zavisi od Settings i kao takav klijent treba da bude svestan da ako zeli da napravi Song objekat treba da pre toga napravi Settings objekat.
Jedino bi ja napravio constructor injection, mada je u principu svejedno da li je setter ili constructor dependency injection. Setter se mnogo vise koristi u TDDu.
Jos je napravljen i interface, tako da bi bilo maksimalno pogodno za bilo koju buducu modifikaciju. Dakle imamo i dizajn po contractu, koji omogucava svu OOP fleksibilnost.

2. Primer ...
Code:

public function getCreatedAt() {    
    $date = new DateTime($this->created_at);
    return $date->format(Settings::getInstance()->getDateFormat()) ;
}

public function getCreatedAt() {    
    $date = new DateTime($this->created_at);
    return $date->format(Translation::getForVisitor()->date_format) ;
}


Po meni ovo nije najcistije napisano. Prvo singleton. Jedna instanca necega je u redu. Ali singleton kao nacin da se to postigne nije najcistije resenje gledano iz ugla TDD, pa cak i OOP dizajna. Sam singleton nije nista nego malo sofisticiraniji global, koga svi znamo ne treba koristiti ni uz pretnju puskom ;)

Druga stvar, direktni poziv Settings u ovoj metodi dovodi do toga da je prakticno dependency hardcodovan.
Ovo je veoma tesko testirati. Upotreba singleton obrasca u TDDu je veoma tesko kontrolisati.

Slicna prica za Translation::getForVisitor(). Ovako napisano ova metoda moze da ima malo vecu logiku koju odradi u pozadini. Npr. treba da proveri da li je korisnik logovan, da vidi koji je to visitor, pa da ode u bazu da vidi njegov jezik, pa na osnovu toga ucita lang fajl itd...
Ne kazem da to radi, ali na osnovu ove linije koda, nije "razumljivo" iz prve sta ta metoda zapravo radi. Ukoliko radi ovo sto sam napisao, ovo je takodje tesko testirati.

3. Ono sto se provlaci kroz ove postove, jeste da se dizajniraju same klase tako da se objekti "ne poznaju" medju sobom.
Na taj nacin, kako bi koristio same klase i objekte, moras da definises jasan API preko koga komuniciraju svi ovi objekti.
Ovo je najbolja stvar koja moze da se desi kada pises neki app ili bilo sta drugo. Ako se uspe tako da organizuje arhitektura, da jedna klasa ne zna za onu drugu (black-box), onda je to super. Sto vise razbijes na manje celine svoju arhitekturu (na gore opisani nacin), to je mnogo bolje i lakse za odrzavanje.
Ukoliko neki objekat koji treba da kreiras zavisi od 4 drugih, tada je najbolje staviti to "kreiranje" u neku factory klasu (DI - dependency injection).
Na taj nacin ako klase koje saradjuju (collaborators) se na bilo koji nacin promene i sl, ti menjas samo na jednom mestu u factory klasi tj. u jednoj njenoj metodi. Sam DI princip koliko vidim postaje sve vise mainstream, tako da ne bi se dzabe potenciralo na tome da ne vredi.
Bacite pogleda na symfony DI ili google Guice. Na taj nacin se izbegava direktno koriscenje new operatora, osim na jednom mestu u factory klasama, pa ovakva organizacija biva veoma pogodna za odrzavanje.
Tu se prica naravno ne zavrsava. Ovo je samo vrh ledenog brega. Onda mnogo toga zavisi i da li je klasa tj. objekat statefull ili stateless. Sve ima svoja pravila, kao i pros&cons. Itd...

$0.02 ;)




[Ovu poruku je menjao _korso_ dana 13.03.2011. u 00:34 GMT+1]
 
Odgovor na temu

krksi
PHP Developer
Beograd

Član broj: 281484
Poruke: 22
95.180.40.*



Profil

icon Re: OOP - principi programiranja13.03.2011. u 05:24 - pre 159 meseci
@_korso_

u potpunosti se slazem.
 
Odgovor na temu

_korso_

Član broj: 82797
Poruke: 163
*.adsl-a-4.sezampro.rs.



+1 Profil

icon Re: OOP - principi programiranja13.03.2011. u 08:10 - pre 159 meseci
@krksi
Tek sada videh detaljnije tvoj prvi post za "ciscenje" - tvoj predlog. Opet da ne ulazimo u detalje da li i ko treba od koga da zavisi (mislim na objekte).
Pricamo kakva jeste postavka sada.

Primer je opet skolski kako napraviti komponente da budu Loose Coupling (http://en.wikipedia.org/wiki/Loose_coupling). Dakle imas contract ("ugovor"), sta jedna klasa/objekat ocekuje da joj se prosledi kako bi mogla da odradi svoj posao. Od ovoga ne moze fleksibilnije. Generalno razmisljas kako sistem funkcionise i tako ga programiras (interface zato i sluzi), a ne razmisljas kroz implementaciju. Vojnik kada dodje u kasarnu ne nosi neki Tool za ciscenje, pa i ne treba da zna o tome nista, sve dok mu neko ne utrapi Tool i kaze cisti.
Tako da je ovo definitivno skolski reseno. Ono sto stoji je da je ovo veoma light primer, ali dovoljan za ilustraciju.
Naravno, u velikim sistemima ovo je malo teze postici ... ovaj nivo decouplinga. Ali da bi projektovao veci sistem treba ti i vise iskustva. A kroz samu praksu i vremenom stices i taj skill da mozes da se i u velikim sistemima igras na ovaj nacin.
Tako da je ovo i vise nego izvodljivo.

Samo jedna napomena.
Code:

class Soldier {
    private $tool;
    
    public function setTool(Tool $tool) {
        $this->tool = $tool;
    }
    public function cleanLeaves() {
        $tool->clean(); //treba $this->tool --- treba ispraviti ---
    }
}

Ako ovo neko cita ko trenutno uci osnove OOP, verovatno ima da se zbuni.
 
Odgovor na temu

krksi
PHP Developer
Beograd

Član broj: 281484
Poruke: 22
95.180.40.*



Profil

icon Re: OOP - principi programiranja13.03.2011. u 08:44 - pre 159 meseci
@_korso_
upravu si, u brzini sam zaboravio na $this, sada sam ispravio to, hvala za sugestiju :)

tako je, ovo je sasvim obican i banalan primer, ukoliko je aplikacija veca, ima vise logike, slozenija je, samim tim je i teze i slozenije primeniti Loose Coupling. Mogu da se nauce osnovne stvari, i treba, ali da bi se to sve lepo skockalo i primenilo, to ne moze da se nauci, jednostavno to se stice iskustvom, bas kao sto si i kazao.

ja samo zelim da ljudima koji krecu da se bave programiranjem i koji krecu da uce OO koncept (u krajnjem slucaju to ne mora ni da bude php, ja sam prvi korake u OOP-u napravio u javi, i tamo naucio skoro sve sto primenjujem sada u php-u), da ukazem kako bi trebalo programirati (da se razumemo, nisam ja to izmislio, vec samo samo ucio od drugih :) )

Kao sto sam vec napomenuo, znanja nikad dosta, pa zato volim da diskutujem sa ljudima na tu temu, jer uvek ima sta novo da se nauci :)
 
Odgovor na temu

_korso_

Član broj: 82797
Poruke: 163
*.adsl-a-4.sezampro.rs.



+1 Profil

icon Re: OOP - principi programiranja13.03.2011. u 09:25 - pre 159 meseci
Ja sam svoje prve programerske korake naucio u C-u i C++ :)

Kasnije je dosla Java i mogu da kazem da mi je dosta pomogla da shvatim principe OOP-a. Ali sto se tice samog OOP, to se ne uci za dan-dva, to je ziv proces, stalno se usavrsavas. Nije toliko ni bitan jezik. Manje-vise u svim jezicima je barem 80% isto, a ostalo su nijasne u implementaciji nekih principa u samom jeziku, sintaksi i sl.

Tako da svaka tema koja se bavi ovom problematikom, moze da nekome ko tek sada pocinje, samo da pomogne. Naravno preduslov je da je sama diskusija objektivna.
 
Odgovor na temu

mitke013
As Divljine
Freelancer

Član broj: 231934
Poruke: 338
*.dynamic.isp.telekom.rs.



+34 Profil

icon Re: OOP - principi programiranja13.03.2011. u 18:01 - pre 159 meseci
Citat:
Song zavisi od Settings i kao takav klijent treba da bude svestan da ako zeli da napravi Song objekat treba da pre toga napravi Settings objekat.


Nisi procitao moj post. Settings je klasa gde admin podesava brdo stvari; paginacija u admin/front delu, default velicina thumb-a, cenu necega, google analytics code, paypal adresa itd. Ta klasa je najkoriscenija u mom programu; mislim da preko 80% ostalih klasi nesto cita iz nje. I dalje sam siguran da moj nacin rada omogucava daleko vecu fleksibilnost. Ono sto vi predlazete je konstantno trpanje novih klasa, novih metoda... Gde je lakse snaci se? Imati 20 klasa koji kao celina odlicno rade, testove da olaksaju upgrade... ili za isti posao imati 50 klasa i siguran sam, mnogo mnogo dupliranih stvari.

Primer koji sam naveo to najbolje ilustruje; meni je trebalo da izmenim SAMO jednu liniju koda i da omogucim drugaciji format datuma u template-u. Nije DI, nije Loose coupling... ali nije ni pretrpavanje nepotrebnim kodom ne bi li mogao da kazem: e to je taj i taj pattern. Teorija je jedno, to se uci na faksu.. ali praksa je nesto drugo. Mogli ste primetiti da ja UVEK pokazujem realan kod i nikad definicije.

Citat:
Po meni ovo nije najcistije napisano. Prvo singleton. Jedna instanca necega je u redu. Ali singleton kao nacin da se to postigne nije najcistije resenje gledano iz ugla TDD, pa cak i OOP dizajna. Sam singleton nije nista nego malo sofisticiraniji global, koga svi znamo ne treba koristiti ni uz pretnju puskom


Porediti singleton i global je kao porediti NASCAR automobil sa yugom koji ima blokirane kocnice. Da li uopste znas zasto i gde se koristi singleton? Dacu ti jedan primer; ta Settings klasa radi sa fajlom. Ja kad pozovem Settings::getInstance(), metoda ce ucitati .ini fajl, parsirati ga i vratiti mi instancu settings klase. Kad sledeci put uradim istu, program ce mi samo vratiti instancu; sigurno necu da mi se iznova i iznova parsira jedan isti fajl. Poredjenje toga i global-a je u najmanju ruku smesno.

Koliko kapiram, ti bi uradio sledece:
Code (php):

$settings = new Settings() ;
$settings->readFile() ;
$nesto = $settings->getNesto() ;

naspram

$nesto = Settings::getInstance()->getNesto() ;
 


Mislim da je razlika i vise nego uocljiva. Ali ako po default-u ne verujes meni, kako to da SVAKI orm koristi prednosti singleton-a do maximuma?

Citat:
3. Ono sto se provlaci kroz ove postove, jeste da se dizajniraju same klase tako da se objekti "ne poznaju" medju sobom.
Na taj nacin, kako bi koristio same klase i objekte, moras da definises jasan API preko koga komuniciraju svi ovi objekti.
Ovo je najbolja stvar koja moze da se desi kada pises neki app ili bilo sta drugo. Ako se uspe tako da organizuje arhitektura, da jedna klasa ne zna za onu drugu (black-box), onda je to super. Sto vise razbijes na manje celine svoju arhitekturu (na gore opisani nacin), to je mnogo bolje i lakse za odrzavanje.


E vidis; ovde je najveca razlika izmedju mene i vas dvojice. Moj nacin rada omogucava lake izmene i nista logike u kontroleru. Vas nacin je da kontroler mora modelu stalno nesto da dodaje, oduzima... Opasna greska! Recenica:
Citat:
Ako se uspe tako da organizuje arhitektura, da jedna klasa ne zna za onu drugu (black-box), onda je to super.

Ja ovo tumacim: imamo neke funkcije koje smo stavili u klasu i to je sad super OOP. Teorija kaze da; tacno to je OOP. Praksa kaze; ok, dobili smo autoload fajlova, malo lepsi kod i ... pa to je to. Fleksibilnost? Nula. Krksi bi na primeru o formatu datuma, sam format stavio u template. Sta se desi kad hoces drugi format, plus da hoces da se format moze menjati iz interfejsa? Ili da zavisi (kao sto sam i uradio) od jezika koji je posetioc (visitor) odabrao?

U oba slucaja je jako velika izmena. Kod mene; jedna linija koda.

Citat:

Slicna prica za Translation::getForVisitor(). Ovako napisano ova metoda moze da ima malo vecu logiku koju odradi u pozadini. Npr. treba da proveri da li je korisnik logovan, da vidi koji je to visitor, pa da ode u bazu da vidi njegov jezik, pa na osnovu toga ucita lang fajl itd...
Ne kazem da to radi, ali na osnovu ove linije koda, nije "razumljivo" iz prve sta ta metoda zapravo radi. Ukoliko radi ovo sto sam napisao, ovo je takodje tesko testirati.


Ovde sam napravio samo jednu gresku; ime metode ne objasnjava sta radi. Pravilnije bi bilo
Code (php):

Translation::getInstanceForVisitor() ;

ili najbolje

TranslationTable::getInstanceForVisitor() ;
 


Ova metoda treba da vrati instancu jezika koju posetioc koristi, ili defaultn-i jezik. U svakom slucaju, nesto mora da vrati. Ta metoda je druga najkoriscenija u mom programu, prva je naravno Settings::getInstance() ;
Kao sto sam objasnio (a vidim nisi procitao cim si pomenuo lang fajlove), to se koristi u svakom query-u jer je program 100% lokalizovan; ne samo sajt, vec i 70% dinamicki kreiranih objekata. Npr. ime kategorije muzike ce biti Rock na eng, Rok na srpkom itd.
Code (php):

          /**
          * Add category with translated name to query:
          *
          * category_name
          *
          * @param Doctrine_Query $query
          */

          protected function addCategory(Doctrine_Query $query)
          {
               $query->innerJoin('o.Category c') ;
               $query->innerJoin('c.CategoryTranslation m WITH m.translation_id=?', Translation::getForVisitor()->id) ;
               $query->addSelect('m.name AS category_name') ;
          }


Vidis fleksibilnost bolje sad? Zamisli da kategorije ranije nisu bile visejezicke. Kod bi tada bio:
Code (php):

          protected function addCategory(Doctrine_Query $query)
          {
               $query->innerJoin('o.Category c') ;
               $query->addSelect('c.name AS category_name') ;
          }

Vidis razliku? Jedna jedina linija koda. NIGDE drugde nema NIKAKVE izmene, samo jedno jedino mesto. Ali bas NIGDE drugde; ja bih ime kategorije kojoj Song pripada i dalje pristupao $song->category_name ili $song->getCategoryName(), svejedno.

Nije DI, nije LC, nije brdo prepisanih definicija sa neta. Ali radi ODLICNO, lako se menja, svako moze da upgrade-uje i nije potrebno zatrpavanje koda ko-zna-cim. API je jako mali i lako se testira. Za settings klasu nisam ni pisao testove; kad bih to radio, jedino bi testirao validaciju, nista vise. Ona je tu da vrati 'nesto'; na pocetku razvoja, to moze biti fiksirano u kodu:
Code (php):

          // paginacija u admin delu
          public function getAdminPageLimit()
          {
               return 10 ;
          }
 

Ako hocu da jednog dana vrednost bude opciona, napravim interfejs za to (koji vec postoji) a kod izmenim:
Code (php):

          public function getAdminPageLimit()
          {
               return $this->admin_page_limit ;  // ovo je pravi kod koji koristim
          }
 

Ako je kontroleru trebala ova informacija, on ce i dalje da radi. NIKAKVIH drugih izmena nije bilo.

Ponovicu se: najlakse je dodavati i dodavati i dodavati... I lako je prepisivati definije sa neta; sve ovo sam ja vec procitao ranije, zaista nema potrebe da radis copy&paste. Nisam najpametniji na svetu, to je sigurno, ali dok ne vidim na prakticnom primeru da je nesto bolje od toga kako radim, necu koristiti. A moji uslovi su jednostavni: API da bude sto manji, da izmena bude sto laksa, da klasa bude sto manje jer necu dupliranje funkcionalnosti... Nisam zahtevan, zaista. Na primeru, molim te.

 
Odgovor na temu

mitke013
As Divljine
Freelancer

Član broj: 231934
Poruke: 338
*.dynamic.isp.telekom.rs.



+34 Profil

icon Re: OOP - principi programiranja13.03.2011. u 18:33 - pre 159 meseci
Citat:
ja samo zelim da ljudima koji krecu da se bave programiranjem i koji krecu da uce OO koncept (u krajnjem slucaju to ne mora ni da bude php, ja sam prvi korake u OOP-u napravio u javi, i tamo naucio skoro sve sto primenjujem sada u php-u), da ukazem kako bi trebalo programirati (da se razumemo, nisam ja to izmislio, vec samo samo ucio od drugih )


Ne znam javu ali koliko sam ukapirao, ti imas brdo vec gotovih uradjenih klasa koje nemaju direktne veze sa tvojim programom. U principu, multipraktik klase. Naravno da je njima neophodno proslediti parametre; oni su tu samo helper-i da ti urade neki posao.
Ako si u C-u nekad radio pod operativnim sistemom, cak i najobicnije otvaranje prozora i kreiranje event-a bude jako puno koda. Logicno; OS ne moze da ti cita misli, moras da mu nacrtas sta hoces. Ali ako koristis na primer SDL, stvar je mnogo laksa. Umesto 30 linija koda, prozor i event-i se definisu u 2-3 linije. SDL ce interno da se pobrine oko ostatka.

Vratimo se sad u realan svet php-a. I ja koristim te multipraktik klase; imam svoju klasu Image koja je deo modela. Npr. Album je one2many sa Image. Ali ta image klasa koristi PhpThumb kao helper. Ja cu mojoj Image klasi reci
Code (php):

$image->resize($_POST['x'], $_POST['y'])  // grub primer kad recimo korisnik moze da promeni velinu
$image->save() // snimi sliku, kreira thumb ciju je velicinu procitao iz Settings klase, kreira novo ime kako bi browser kesirao, obrise stare fajlove ako ih je bilo
 


Kako ce to ona da resi? Koga briga u trenutku dok pisem gornju liniju. Interno, Image ce koristiti PhpThumb. Ako jednog dana hocu neki drugi helper, samo izmenim resize() metodu i SVE ostalo ce da radi. Da program radi, znacu kad pustim testove koje sam ranije napisao. E to se zove upgrade programa.

Takodje koristim i getId3() za validaciju uploadovanih pesama. Imam moju klasu Song, to je klasa modela mog programa; User je one2many sa Song, Album je one2many sa Song... tu su jos i kategorija, jezik itd... getID3 je samo helper, NISTA vise.

I naravno da svim tim helperima moram slati parametre; to su multipraktik programi koji zaista nisu deo modela, koji rade sve i svasta i ne mogu da mi citaju misli. Ja kad uradim:
Code (php):

$song->isValid() ;
 

zaista samo zelim da znam da li je korisnik poslao pravu pesmu (.mp3, .wav itd) a ne neki php kako bi mi nesto pokvario. Interno; Song poziva getID3 paket. Mozda ce jednog dana koristiti getID4-turbo-mega-ultra paket, nije nimalo bitno jer ja i dalje menjam samo jednu jedinu metodu. Ne dodajem nista, ne menjam kontrolere, ne menjam druge modele.

Nadam se da razumes sta hocu da kazem. Trebao bi napraviti razliku izmedju helper klasa i klasa modela. Klase modela su srce tvog programa i ne treba ih pisati kao multi-praktik pa da im moras 'crtati' sta treba da rade. Jel onaj vojnik toliko glup pa ne ume metlu sam da uzme? Ili usisivac? Zasto bi ih kreirao toliko glupe i samim tim, stavljao logiku u kontroler?
 
Odgovor na temu

_korso_

Član broj: 82797
Poruke: 163
*.adsl-a-4.sezampro.rs.



+1 Profil

icon Re: OOP - principi programiranja13.03.2011. u 19:53 - pre 159 meseci
Posto citiranje ne radi pa moram da improvizujem
Citat:

Nisi procitao moj post. Settings je klasa gde admin podesava brdo stvari; paginacija u admin/front delu, default velicina thumb-a, cenu necega, google analytics code, paypal adresa itd. Ta klasa je najkoriscenija u mom programu; mislim da preko 80% ostalih klasi nesto cita iz nje. I dalje sam siguran da moj nacin rada omogucava daleko vecu fleksibilnost.
.
Post jesam procitao. Ovde ti gresis. Settings klasa ne treba da zna da li je neko admin ili ne. Taj dependency treba da injectujes na neki nacin u Settings klasu i tako da odradis to sto tebi treba. Zamisli da Settings klasu hoces da koristis u dva projekta gde u jednom nema admin role. Sta bi onda radio? Moras da je menjas - ovako imas Settings koji uvek radi na isti nacin, samo su uslovi pod kojima nesto ucitava razliciti. Zbog toga mislim da ne omogucava veliku fleksibilnost. Jedino sto mozda ti nemas potrebe za tim u tvom projektu.

Citat:

Ono sto vi predlazete je konstantno trpanje novih klasa, novih metoda... Gde je lakse snaci se? Imati 20 klasa koji kao celina odlicno rade, testove da olaksaju upgrade... ili za isti posao imati 50 klasa i siguran sam, mnogo mnogo dupliranih stvari.

Niko to ne predlaze i niko nije rekao. Sistem koji je krksi opisao je skolski primer, da se ne ponavljam. Loose coupling kaze da nema dupliranja. Ovo si lose protumacio.

Citat:

Primer koji sam naveo to najbolje ilustruje; meni je trebalo da izmenim SAMO jednu liniju koda i da omogucim drugaciji format datuma u template-u. Nije DI, nije Loose coupling... ali nije ni pretrpavanje nepotrebnim kodom ne bi li mogao da kazem: e to je taj i taj pattern. Teorija je jedno, to se uci na faksu.. ali praksa je nesto drugo. Mogli ste primetiti da ja UVEK pokazujem realan kod i nikad definicije.

Ja faks nisam zavrsio i tu teoriju neces naci na faksu. Ali sam procitao nesto od knjiga o OOP programiranju, metodologiji, principima.
Baci pogled na ovo http://flow3.typo3.org/documentation/books/. Tu sve pise. Dakle nema pretrpavanja nepotrebnim kodom.
Niko ne projektuje tako sto ce da kaze sada cu da koristim ovde Memento pattern. Ako znas patterne, ti na osnovu problema koji resavas identifikujes koji pattern moze da ti zavrsi posao. Takodje, skoro nikad se primena patterna ne radi 100% kao sto je u teoriji. Uvek imas tweak tamo ili ovamo.
Dobro dizajniranom sistemu takodje nije bitno da li ima par linija koda vise ili manje. Ali u celini, kada se sve sabere, uvek dobijes manje koda, to je de-facto.

Citat:

Porediti singleton i global je kao porediti NASCAR automobil sa yugom koji ima blokirane kocnice. Da li uopste znas zasto i gde se koristi singleton?

Mislim da sam isuvise korektan da bi se vredjali i samo sam dao svoj doprinos temi. Da li ja znam sta je Singleton... mislim da nije u redu. Sta ti mislis ?!!

Citat:

Dacu ti jedan primer; ta Settings klasa radi sa fajlom. Ja kad pozovem Settings::getInstance(), metoda ce ucitati .ini fajl, parsirati ga i vratiti mi instancu settings klase.

Settings klasa ne treba da ucitava fajl. To ti odgovorno tvrdim. Njoj treba da se doture isparsirane vrednosti ili sta vec. A onda iz nje iscitavas sta ti treba.
Eventualno da imas factory za SettingsIni, SettingsDB ... koji imaju u pozadini neku abstract klasu Settings. Ali to zavisi od puno stvari kako bi se implementiralo.

Citat:

Kad sledeci put uradim istu, program ce mi samo vratiti instancu; sigurno necu da mi se iznova i iznova parsira jedan isti fajl. Poredjenje toga i global-a je u najmanju ruku smesno.

To niko nije ni rekao da ce da ucitava fajl 100 puta. Singleton jeste global. Singleton===global. Sta mislis zasto ?

Citat:

Mislim da je razlika i vise nego uocljiva. Ali ako po default-u ne verujes meni, kako to da SVAKI orm koristi prednosti singleton-a do maximuma?

Ne zelim da te uvredim, ali ORM nije centar sveta. Singleton ja koristim samo kada moram, ali single insancu jedne klase bez singletona vrlo cesto.
Vrlo slicno kao sto si napisao. Samo sto to stoji u DI containteru ili sta vec koristim.

Citat:

E vidis; ovde je najveca razlika izmedju mene i vas dvojice. Moj nacin rada omogucava lake izmene i nista logike u kontroleru. Vas nacin je da kontroler mora modelu stalno nesto da dodaje, oduzima... Opasna greska!

Ovde ne pricamo o implementaciji kroz controllere, modele i helpere vec o teoriji. MVC nije jedini web pattern.
MVC kao sto se upotrebljava po defaultu, ja nesto preterano i ne korsitim, jer ne radim na taj nacin i takve projekte.
Koristim zadnje 4 godine RIA (http://en.wikipedia.org/wiki/Rich_Internet_application) . JS frontend, PHP backend. PHP ti je delom implementiran kroz DDD (trenutno radim na prebacivanju cele biznis logike na DDD). Tako da i ja imam veoma lake izmene u kodu, a da ne koristim klasicno shvatanje MVC-a.
A klasican MVC sam radio npr. ovde http://www.singtotheworld.com/, pre jedno 5 godina. Mada je sajt pretrpeo neke izmene kako sad videh.

Citat:

Ja ovo tumacim: imamo neke funkcije koje smo stavili u klasu i to je sad super OOP. Teorija kaze da; tacno to je OOP. Praksa kaze; ok, dobili smo autoload fajlova, malo lepsi kod i ... pa to je to. Fleksibilnost? Nula. Krksi bi na primeru o formatu datuma, sam format stavio u template. Sta se desi kad hoces drugi format, plus da hoces da se format moze menjati iz interfejsa? Ili da zavisi (kao sto sam i uradio) od jezika koji je posetioc (visitor) odabrao?
U oba slucaja je jako velika izmena. Kod mene; jedna linija koda.

Ovo stvarno ne bih da komentarisem. Izmena je onolika kolika treba da bude. Sve zavisi od situacije. Ali gore sam negde vec objasnjavao DI princip. Fleksibilnost je ~85%. Ovih 15% otpadaju na to da se sistem izmeni iz korena.

Citat:

Nije DI, nije LC, nije brdo prepisanih definicija sa neta.

Jel ovo u redu, sta ti mislis ?!!

Citat:

Ali radi ODLICNO, lako se menja.

Ok, ako se menja lako, super.

Citat:

Svako moze da upgrade-uje i nije potrebno zatrpavanje koda ko-zna-cim.

Ponavljam nista se ne zatrpava.

Citat:

Ponovicu se: najlakse je dodavati i dodavati i dodavati... I lako je prepisivati definije sa neta; sve ovo sam ja vec procitao ranije, zaista nema potrebe da radis copy&paste. Nisam najpametniji na svetu, to je sigurno, ali dok ne vidim na prakticnom primeru da je nesto bolje od toga kako radim, necu koristiti.

Ne zelim da idem u off i da mi administrator sece post (sto bih istog i molio, jer sam da kazem prozvan licno i treba da imam prilike da odbranim svoje stavove). Preispitaj samo opet sta si rekao? Ja tebi ovde nisam savetovao kako da radis. Moje ucestvovanje u temi nije bilo da kazem kako da radis ti ili bilo ko drugi, vec je bilo uopsteno kakva su moja iskustva. I zbog toga sto sam se slozio sa krksijem, a ne sa tobom, nemam nista protiv tvog nacina rada, ako tebi zavrsava posao.

Nadam se da sam bio jasan.

[Ovu poruku je menjao _korso_ dana 13.03.2011. u 23:07 GMT+1]

[Ovu poruku je menjao _korso_ dana 13.03.2011. u 23:09 GMT+1]
 
Odgovor na temu

mitke013
As Divljine
Freelancer

Član broj: 231934
Poruke: 338
*.dynamic.isp.telekom.rs.



+34 Profil

icon Re: OOP - principi programiranja13.03.2011. u 22:47 - pre 159 meseci
Citat:
P
Nisi procitao moj post. Settings je klasa gde admin podesava brdo stvari; paginacija u admin/front delu, default velicina thumb-a, cenu necega, google analytics code, paypal adresa itd. Ta klasa je najkoriscenija u mom programu; mislim da preko 80% ostalih klasi nesto cita iz nje. I dalje sam siguran da moj nacin rada omogucava daleko vecu fleksibilnost.
.
Post jesam procitao. Ovde ti gresis. Settings klasa ne treba da zna da li je neko admin ili ne. Taj dependency treba da injectujes na neki nacin u Settings klasu i tako da odradis to sto tebi treba. Zamisli da Settings klasu hoces da koristis u dva projekta gde u jednom nema admin role. Sta bi onda radio? Moras da je menjas - ovako imas Settings koji uvek radi na isti nacin, samo su uslovi pod kojima nesto ucitava razliciti. Zbog toga mislim da ne omogucava veliku fleksibilnost. Jedino sto mozda ti nemas potrebe za tim u tvom projektu.


Mozes da se osecas uvredjenim ako hoces, ali ovde si potvrdio da nisi citao moje postove. Ja nigde nisam rekao da Settings klasa zna ista o adminu; ono je samo broj rezultata za paginaciju u admin delu programa. Cak sam postavio sliku i dao primere koda. Mislio sam da je jasno objasnjeno uloga te klasa; konfiguracija.

Ok, mozda je ime klase zbunjujuce, bolje bi bilo Config ili slicno. Ali poentu sam dovoljno jasno objasnio.

Citat:
Settings klasa ne treba da ucitava fajl. To ti odgovorno tvrdim.

Zasto?
Citat:
Njoj treba da se doture isparsirane vrednosti ili sta vec. A onda iz nje iscitavas sta ti treba.

Ako sam dobro razumeo; 'neka' klasa (nije vazno koja) treba da isparsira .ini fajl, posalje je Settings-u, a ona zatim vraca te parsovane vrednosti? Zar ne vidis koliko je to suvisnog koda za obicnu konfiguraciju?
Citat:
Eventualno da imas factory za SettingsIni, SettingsDB ... koji imaju u pozadini neku abstract klasu Settings.

Settings klasa nasledjuje BaseIni klasu. Ako hocu da jednog dana to bude .txt file, napravicu novu BaseTxt klasu, Settings ce nju da nasledjuje a ceo API ostaje isti. Poenta: ako hocu da izmenim nacin kako Settings radi, izmenicu samo settings.

Citat:
Ali to zavisi od puno stvari kako bi se implementiralo.

Primer?
Citat:
To niko nije ni rekao da ce da ucitava fajl 100 puta. Singleton jeste global. Singleton===global. Sta mislis zasto ?

Singleton
Global
Nije isto.
Citat:
Ne zelim da te uvredim, ali ORM nije centar sveta.

Ne i mog Da mi klijent ponudi 3 puta vise para pod uslovom da ne koristim ORM (nebitno koji), ne bih pristao. ORM mi najmanje 10 puta ubrzava rad.
Poenta recenice da ljudi mnogo pametniji od nas ovde, koriste singleton non-stop jer su prednosti ogromne.
Citat:
Singleton ja koristim samo kada moram, ali single insancu jedne klase bez singletona vrlo cesto. Vrlo slicno kao sto si napisao. Samo sto to stoji u DI containteru ili sta vec koristim.


Ne kapiram; daj mi primer za konfiguraciju. Znaci ono sto radi moja Settings klasa.

Citat:
Ovo stvarno ne bih da komentarisem. Izmena je onolika kolika treba da bude..

To je ono sto i pokusavam da objasnim. Ja sam zeleo samo drugi prikaz datuma. I uradio sam ga kroz izmenu jedne linije.
Citat:
Sve zavisi od situacije. Ali gore sam negde vec objasnjavao DI princip. Fleksibilnost je ~85%. Ovih 15% otpadaju na to da se sistem izmeni iz korena.


E to mi je smetalo, i to veoma. Ako odes na sajt php.net, videces objasnjenje. Ali takodje i puno primera. Tu se razlikujemo; ja kako radim objasnjavam na primeru programa, a ne necega sto se inace moze procitati.
Primere za DI sam video preko simfony 2 sajta, jos pre par meseci. Lepo, simpaticno, ali za ovo o recu pricamo, bespotrebno komplikovanje koda. Ja se drzim KISS principa.

Citat:
Citat:
Nije DI, nije LC, nije brdo prepisanih definicija sa neta.

Jel ovo u redu, sta ti mislis ?!!

Ok, mozda i nije. Ali gore sam opisao sta mi smeta. Ako te uvredilo, izvini, ali suv tekst bez primera za mene nije konstruktivna rasprava. Bar ne na temu programiranja.
Ne zaboravi da programiranje nije egzaktna nauka; problem se uvek moze resiti na vise od jednog nacina.

Ali ovo mi najvise zasmetalo:
Citat:
Ponavljam nista se ne zatrpava.


Ti si se slozio sa krksijem koji je rekao:
Citat:
Tacno je da se broj klasa drasticno povecava, ali zato kasnije mnogo manje imas problema sa izmenama.


Vidis kontradiktornost?

Btw; proucio sam RIA i mislim da mi je jasno zasto ovo predlazes. RIA je skup multi-praktik klasa i njima moras da prosledis gomilu parametara kako bi uopste radilo. Pogledaj moje objasnjenje o C-u i radom pod operativnim sistemom i videces da je isto.

Ali te klase su helper-i; to nije biznis logika. QuickPHP (jedan od RIA fw-a) nema nikakve veze sa tim; to ja pokusavam da objasnim sve vreme. Velika je razlika izmedju biznis logike i helper klasa, opisao sam gore na primerima.




 
Odgovor na temu

Goran Rakić
Beograd

Moderator
Član broj: 999
Poruke: 3766

Sajt: blog.goranrakic.com


+125 Profil

icon Re: OOP - principi programiranja13.03.2011. u 23:43 - pre 159 meseci
Mitke i ja smo već puno puta raspravljali, ali hajde da pokušamo još jednom, možda ovaj put upali.

Imaš singleton Settings. Njega praviš prvi put negde u početku izvršavanog koda i formiraš mu stanje. Pretpostavimo da taj singleton nije trivijalan, tj. da recimo on čita podatke iz INI datoteke, a format datuma ti je u MySQL tabeli.

Code (php):

$format = ...;
Settings::getInstance()->setFormat($format);
 


Nakon bilo koje ovakve operacije (opet, pretpostavimo da Singleton nije trivijalan već da ima neku inicijalizaciju) tvoj singleton više nije isti, stanje mu se promenilo. Negde kasnije u izvršavanju imaš kod koji koristi stanje singletona:
Code (php):

class Something {
  public function doSomething() {
    echo Settings::getInstance->getFormat();
  }
}
 


Kada pišeš unit test za doSomething moraš da konfigurišeš Settings singleton, jer ponašanje doSomething zavisi od njegovog stanja. Stanje ovog singletona je sačuvano u globalno vidljivom prostoru. Bilo koji deo koda može da dohvati instancu i da neprimećeno menja stanje, baš kao i sa globalnim promenljivama.

Ukoliko se dogodi da budeš malo zaboravan, može ti se dogoditi da stanje singletona bude neodgovarajuće. Svi tvoji unit testovi prolaze, ali u praksi kod ne radi. Da je format ili ceo Settings propisno negde ubrizgan u Something objekat, ta zavisnost bi bila odmah vidljiva i pisao bi se složeniji test koji testira da li je odgovorajući Settings ubrizgan. Ovako, pošto je prodor u globalni prostor skriven, dogodi se previd.

Da ponovim, baš kao i kod globalnih promenljivih, singleton svoje stanje čuva dostupno i vidljivo svima. Objekti koji pozivaju singleton mogu da jedan drugome pomrse račun. Singleton je malo bolji jer može da upravlja sopstvenim stanjem, ali suštinski nema velike razlike.

Ovo ne znači da se singleton nigde ne koristi, daleko od toga. Isto tako i globalne promenljive imaju svoju ulogu, i ubrizgavanje, i parametri u metodama, sve su to tehnike koja jednu drugu dopunjuju.

http://sr.libreoffice.org — slobodan kancelarijski paket, obrada teksta, tablice,
prezentacije, legalno bez troškova licenciranja
 
Odgovor na temu

_korso_

Član broj: 82797
Poruke: 163
*.adsl-a-4.sezampro.rs.



+1 Profil

icon Re: OOP - principi programiranja13.03.2011. u 23:50 - pre 159 meseci
Bicu kratak. Ne zelim da nista ne kazem i da ispadne da sam se samo povukao.
Takodje ne zelim da zagadjujem dalje temu, nasim da kazem verbalnim prepucavanjem.

Definitivno da ti mene ne razumes i da neke stvari u programiranju ne razumes. Imas svoj svet i svoju pricu i to furas.
Ja sam imao dobru nameru na pocetku da ucestvujem u konstruktivnoj diskusiji, ali je to dzabe.
Da ti objasnjavam neke stvari po 3. put, stvarno nemam vremena i zivaca.
Da neka tvoja izvlacenja iz konteksta, rasclanjujem i analizram i da se pravdam, stvarno nemam vremena a i ni potrebe.
Ako ne razumes, a imas takav arogantan stav, nikada neces ni da shvatis. Licno nemam nista protiv tebe, redak si slucaj koji zeli da svakom objasni nesto, ali mislim da ga preterujes cim neko kaze nesto sto se protivi tvojim shvatanjima, a uz to i vredjas.

Da li vidis da ti sasvim korektno odgovaram? Da li i ti mozes tako?

Ono sto je istina da na ovaj tvoj post, zelim da odgovorim i mogu da ti napisem roman, ali mislim da se ovako objasnjavamo nema totalno smisla.

Da zakljucim, tvoj stav ,daj mi primer, a ne teoriju ... to je jeste ok, ali moras i ti da shvatis, da jednostavno neki ljudi nemaju vremean da pisu i trose po n sati na elaboriranje odredjenih problema. Zato i sluzi teorija. A zele koliko-toliko da daju doprinos [ES] zajednici.

Toliko. Za mene je ova diskusija zavrsena.
 
Odgovor na temu

mitke013
As Divljine
Freelancer

Član broj: 231934
Poruke: 338
*.dynamic.isp.telekom.rs.



+34 Profil

icon Re: OOP - principi programiranja14.03.2011. u 00:35 - pre 159 meseci
Citat:
Imaš singleton Settings. Njega praviš prvi put negde u početku izvršavanog koda i formiraš mu stanje. Pretpostavimo da taj singleton nije trivijalan, tj. da recimo on čita podatke iz INI datoteke, a format datuma ti je u MySQL tabeli.


Ok, zamislimo da je tako. U praksi mi je to obican string koji ce vlasnik sajta da menja iz web interfejsa. Ali nije bitno, cisto kao ideju da dodam.
Citat:
Nakon bilo koje ovakve operacije (opet, pretpostavimo da Singleton nije trivijalan već da ima neku inicijalizaciju) tvoj singleton više nije isti, stanje mu se promenilo. Negde kasnije u izvršavanju imaš kod koji koristi stanje singletona:


Pa TO i kazem; singleton ce imati neku inicijalizaciju. Nije bitno da li je to .ini fajl, .txt fajl, mozda i baza jednog dana (mada je to bezveze za config al ajde). Bitno je sto ce po kreiranju instance da se sva ta priprema obavi i od tada pa nadalje samo koristim vec obradjene podatke.

Citat:
Ukoliko se dogodi da budeš malo zaboravan, može ti se dogoditi da stanje singletona bude neodgovarajuće. Svi tvoji unit testovi prolaze, ali u praksi kod ne radi. Da je format ili ceo Settings propisno negde ubrizgan u Something objekat, ta zavisnost bi bila odmah vidljiva i pisao bi se složeniji test koji testira da li je odgovorajući Settings ubrizgan. Ovako, pošto je prodor u globalni prostor skriven, dogodi se previd.


Uf... ovo me totalno zbunilo. Gle; taj settings je samo klasa za konfiguraciju programa. Ovo sto si rekao:
Code:
Settings::getInstance()->setFormat($format);


treba samo da bude
Code:
Settings::getInstance()->setFormat($format)->save();


Ako hoces da trajno snimis config. Ako ne; nakon izvrsavanja php script-e, hasta li vista!

Ali ljudi, pa to je obican config. Settings nema nikakvu logiku; kad je neko pita: e setting-u, daj mi cenu contest-a, on ce da je vrati. A cena contest-a se menja kao ovo gore:
Code:
Settings::getInstance()->setContestPrize($_POST['prize')->save(); // recimo da je tako, fali poziv isValid() itd ali samo primer 


Kad model Image pita; setting-u, na koliko da kreiram thumbnail, ovaj ce da mu to i kaze. Ako admin jednog dana promeni tu vrednost, sledeci put kad Image pozove dobice te nove vrednosti.

Mislim... vrlo jednostavno, uopste ne kapiram potrebu za komplikovanjem necega.

Ono sto je realan scenario:
Nikad, ali bas nikad se nece desiti da neko dinamicki menja Settings. To je kao kad koristis konfiguraciju za tvoj program; eto, broj rezultata po stranici je dobar primer. Obicna brojka! Niko je nece menjati, osim admin i to verovatno jednom i nikad vise. Settings nije tu da ga svaki cas neki model menja, zaista.
Meni se cini da niste razumeli namenu te klase.

Citat:
Ako ne razumes, a imas takav arogantan stav, nikada neces ni da shvatis. Licno nemam nista protiv tebe, redak si slucaj koji zeli da svakom objasni nesto, ali mislim da ga preterujes cim neko kaze nesto sto se protivi tvojim shvatanjima, a uz to i vredjas.

Veruj, da si mi ti rekao; "mitke j**i se vise, triput sam ti dao primer, sta sad hoces vise" ili slicno, ja se zaista ne bih uvredio. Ali ako zaista nisam procitao.

Citat:
Da zakljucim, tvoj stav ,daj mi primer, a ne teoriju ... to je jeste ok, ali moras i ti da shvatis, da jednostavno neki ljudi nemaju vremean da pisu i trose po n sati na elaboriranje odredjenih problema. Zato i sluzi teorija. A zele koliko-toliko da daju doprinos [ES] zajednic

Yep! Ali kad se sudare teorija i praksa, stavljaju se primeri.

Vidis; ovde ima clanova koji nemaju blage veze o OOP-u. Recimo, skoro su poceli da uce, ne znaju sta je dobro, sta je lose... Sta ce im vise pomoci? Primer ili teorija? Sta kad hoces brdo teorije da stavis i tamo gde mu nije mesto? Konkretno; ja i dalje smatram da config klasa Settings ne treba da koristi DI. I smatram da guranje DI-a u nju je bespotrebno komplikovanje programa, samo da bi se reklo 'e koristim DI'.

Mozda gresim, ali sam zato i pitao za primer. Teorije sam se vala nacitao dosad; a sve je pocelo od 'class Dog extends Animal'

Scenarija je mnogo. Ni ja nemam previse vremena; klijenta zavlacim vec mesec dana minimum, drugi me ganja da sto pre pocnemo mobilnu verziju, da bi posle toga radili shoping karticu za nov program... Pa opet hocu da nekom ukazem na realne situacije jer ce to neko mozda iskoristiti i unovciti. Ja zaista zelim da i drugi zarade; mogao bih i ja sebicno da drzim znanje samo za sebe zar ne? Mislis da meni nije lakse da gledam neki 'no brain no pain' film umesto da nekom ukazem, kroz primere zasto smatram da je nesto lose.

Mogao bih.



 
Odgovor na temu

mitke013
As Divljine
Freelancer

Član broj: 231934
Poruke: 338
*.dynamic.isp.telekom.rs.



+34 Profil

icon Re: OOP - principi programiranja14.03.2011. u 00:59 - pre 159 meseci
U stvari, promena plana, necu vise smetati. Ionako je sav moj trud bio bez ikakvog efekta. Na stackoverflow je ipak drugacija prica.

I da znam, znam... zvuci kao 'drama queen'

btw; ako nekome treba moja pomoc nek me kontaktira na moj_username @gmail.com

 
Odgovor na temu

Goran Rakić
Beograd

Moderator
Član broj: 999
Poruke: 3766

Sajt: blog.goranrakic.com


+125 Profil

icon Re: OOP - principi programiranja14.03.2011. u 01:21 - pre 159 meseci
Jesmo li te naljutili?
http://sr.libreoffice.org — slobodan kancelarijski paket, obrada teksta, tablice,
prezentacije, legalno bez troškova licenciranja
 
Odgovor na temu

[es] :: PHP :: OOP - principi programiranja

Strane: 1 2

[ Pregleda: 9107 | Odgovora: 34 ] > FB > Twit

Postavi temu Odgovori

Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.