Farenji | dinsdag 22 januari 2008 @ 21:45 | |||||||||||
Ik merk dat heel veel mensen op dit forum moeite hebben met Object Oriented Programming. Het wordt ook als iets heel ingewikkelds gezien, terwijl het (als je het eenmaal doorhebt) zo helder en vanzelfsprekend is, dat je niet meer weet waarom je het ooit niet begrepen hebt. Maar zo makkelijk is dat nou ook weer niet. Ik heb er zelf ook flink mee geworsteld in het begin. Misschien kan ik dat jullie besparen met een tutorial/case study in OO perl. Je leert er over object georienteerd programmeren en hebt aan het eind nog een handige bouwsteen voor je OO applicaties ook! Ik heb perl gekozen omdat dat mijn favoriete taal is, maar alle begrippen en zelfs het object dat we gaan maken zijn ook in andere talen toepasbaar/implementeerbaar. Ik zal proberen er geen heel perl specifieke dingen in te doen. We gaan hier een object maken dat je in je eigen objectmodel als basis kan gebruiken, en je heel veel tijd kan gaan schelen. Hoe vaak heb je niet een "select * from table" gedaan, waarna je met "while ($row = mysql_fetch_row($result))" oid een array vulde, of de row naar het scherm printte? Hoe vaak heb je niet editformuliertjes gemaakt waar je records mee kan bewerken en toevoegen? Hoe vaak heb je niet gedacht: "verdomme, doe ik nu weer hetzelfde?" Ik heb dat heel vaak gedacht en ik ben als programmeur van nature lui dus heb ik een mooie abstracte implementatie gemaakt, object georienteerd. Het eindresultaat is best cool geworden. Te cool om alleen voor mezelf te houden. De DataRow class is een heel goed voorbeeld van wat OOP voor je kan doen en hoe het werkt. Heel vaak doe je eigenlijk hetzelfde, met oppervlakkige verschillen. We maken nu een uniforme interface (een API, Application Programming Interface) om als een object met datarecords in databasetabellen om te gaan. Het wordt geen absolute beginnerstutorial, in de zin: ik ga ervan uit dat je wel een beetje kan programmeren en weet hoe dingen als variabelen, conditionals, loops etc werken. Ik zal dingen wel zoveel mogelijk toelichten, met een klein beetje PHP kennis moet je dit wel kunnen volgen. Als je de dingen uit deze tutorial zelf wil uitproberen, heb je voorlopig alleen perl nodig (later halen we er enkele perl libraries bij om wat specifieke dingen te doen). Bij de meeste OS'en is perl standaard aanwezig, maar mocht je zo'n OS hebben waar het niet bij zit: op http://www.activestate.com/ kun je het downloaden. Eerst wat voorbeelden van toepassingen van het eindproject. Stel je hebt een mysql table "pages" vol gegevens, met de velden: ID, title, content, bgcolor. En je wil een CMS systeem maken om deze tabel te bewerken. Dat is heel makkelijk:
Makkelijk he! Ook zonder iets van programmeren te weten kun je wel raden wat er hier ongeveer gebeurt. En er is nog veel meer mogelijk. Hoe werkt dit nou? We beginnen bij het begin: bij het Model. Object georienteerd programmeren betekent dat je werkt met objecten, dus laten we dat object gaan definieren. Welke eigenschappen heeft het, hoe kan je die eigenschappen uitlezen en aanpassen, en wat kan je er allemaal nog meer mee? We gaan ons hier nog niet druk maken om userinterfaces, weergave of programmaflow, dat komt later. Nu eerst de basis. Dat doen we in een bestand, DataRow.pm. In Perl heet dat een package. Dat begint met de naam van het package. Verder bevat het op zijn minst hoe een nieuw object van de DataRow classe gemaakt kan worden. Dit heet de constructor functie, en die heet meestal new(). Met "DataRow->new()" maak je dus een nieuw DataRow object aan.
Wat we nu hebben bereikt is: we hebben nu een structuur voor ons object. Het heeft de properties "ID", "fields", en "dbTable". "fields" is een assoc.array waar de velden en hun values instaan. We kunnen nu dus al een representatie maken van een gewone tabel in een sql database. De enige vereiste is dat er een ID veld is, de rest is flexibel. We maken om het te testen een apart scriptje aan, page1.pl:
Maak het bestand uitvoerbaar met "chmod +x page1.pl" en voer het uit met "./page1.pl" Je ziet dat ik niet alle argumenten heb gespecificeerd. Ik heb het veld ID weggelaten, maar het veld zit toch in het object. Het wordt gevuld met de defaultwaarde 0 die we hebben gedefinieerd in de constructor functie. We kunnen er nu nog weinig mee. Maar dit was les 1. Volgende keer gaan we kijken hoe we netjes eigenschappen van het object kunnen uitlezen en aanpassen mbv object methods. Daarna gaan we ook zorgen dat we rows uit een database kunnen halen en weer op kunnen slaan. Vragen? Stel ze! | ||||||||||||
Wolfje | dinsdag 22 januari 2008 @ 22:11 | |||||||||||
Is perl wel een echte object georienteerde taal? Het ziet er namelijk uit als wat geknutsel om een oo effect te krijgen. De naam 'package' doet vermoeden dat je dat woord ook kunt gebruiken om een aantal methodes te groeperen onder een gezamenlijke naam. En 'new' lijkt een doodgewone methode. Kun je in perl dan ook subclasses maken? | ||||||||||||
Farenji | dinsdag 22 januari 2008 @ 22:18 | |||||||||||
quote:De implementatie in perl is inderdaad anders dan in sommige andere talen, het is er pas later "ingeklust" maar is wel volledig en heel elegant (vind ik persoonlijk). Je kan er alles mee wat je moet kunnen, dus kun je ook subclasses maken waarvan je erg flexibel kan overerven, hier kom ik misschien later nog op terug in deze tutorial. En new() is inderdaad een gewone functie. Je kan de constructor ook nieuw() of poep() noemen, daar ben je vrij in. In perl heb je heel veel vrijheid. En ja, je kan een package ook gebruiken voor een verzameling gerelateerde functies. Het een sluit het ander niet uit. Dat zijn gewoon class methods, in tegenstelling tot object methods: ze doen niks met een object maar staan min of meer op zichzelf. In php of c++ of welke taal dan ook kan dat natuurlijk ook wel. | ||||||||||||
slakkie | woensdag 23 januari 2008 @ 08:15 | |||||||||||
Waarom bless je niet $args? $self is een copy ervan. Volgende keer komt inheritance aan bod? | ||||||||||||
Farenji | woensdag 23 januari 2008 @ 09:22 | |||||||||||
quote:Omdat ik controle wil hebben over wat ik in mijn object krijg, en je niet zomaar bagger erin kan stoppen. Je kan ook argumenten hebben die je niet, of in een andere vorm in je object wil stoppen. | ||||||||||||
Farenji | woensdag 23 januari 2008 @ 21:47 | |||||||||||
Weinig respons, leest iemand dit eigenlijk wel? Anyway ik ga gewoon door. :) Vorige keer hebben we de structuur van het object DataRow gedefinieerd, met als properties de velden ID, fields en dbTable. Het is een generieke class voor een rij gegevens uit een databasetabel. Dit klinkt allemaal nogal abstract. Laten we het dus wat minder abstract maken, en een echte applicatie maken. We gaan een databasesysteem maken om een muziekverzameling in op te slaan! Hiervoor moeten we een database met wat tabellen maken. We houden het simpel, 3 tabellen die een onderlinge relatie hebben:
En nu we tabellen hebben, moeten we een verbinding maken tussen ons DataRow object en de database. We maken dus de objectmethods "load" en "save" aan.
We missen nog wat functies die hierboven gebruikt worden, om de velden en hun inhoud uit te lezen en te wijzigen:
Zo! Nu hebben we een echt functioneel object, waar we al best wat mee kunnen. En dat object schreeuwt erom om ge'subclass'd te worden. Subclassen betekent: maak een nieuwe class die alle eigenschappen van de parentclass "overerft". Het leuke aan subclasses is dat je alles kan herdefinieren. Zo begin je dus al met een basis, waarvanuit je verder kan bouwen, het principe van building blocks. Je wil namelijk geen dubbel werk doen! We maken een nieuwe class aan in het bestand Artist.pm. Hierin zetten we:
Zo! Dat was dat! We kunnen nu makkelijk een nieuw Artist object maken met:
De setField en save methodes heeft Artist gewoon geerfd van DataRow, die hoeven we niet te herdefinieren. Datzelfde truukje kunnen we natuurlijk ook met Album en Song doen:
En hoe het nou met Song.pm moet, kun je vast wel zelf bedenken. :P Volgende keer gaan we kijken wat de samenhang tussen deze objecten is, en hoe we ze handig met elkaar kunnen laten samenwerken! Dan begint de echte kracht pas! *O* | ||||||||||||
slakkie | woensdag 23 januari 2008 @ 22:03 | |||||||||||
Overigens, voor de mensen die geen perl snappen, het cijfer 0, de string 0 of string '' (leeg dus) gelden als undefined binnen Perl.
Dit even ter verduidelijking, aangezien er wellicht wat mensen gaan zeggen, maar ID was 0 hoe kan ie dan saven?!? [ Bericht 36% gewijzigd door slakkie op 24-01-2008 13:29:24 ] | ||||||||||||
Anthraxx | donderdag 24 januari 2008 @ 10:30 | |||||||||||
Persoonlijk vind ik het handiger om OOP uit te leggen met een taal die daar wel voor ontworpen is, en niet met een taal dat het er later bij heeft gehackt (zoals PHP en Perl). | ||||||||||||
Aibmi | donderdag 24 januari 2008 @ 10:34 | |||||||||||
quote:Eens. Sowieso denk ik dat mensen die het bovenstaande een beetje kunnen lezen al OO kunnen programmeren. Als je een complete leek bent snap je er niks van, want dan snap je nog geeneens wat een functie is, wat return types zijn, wat parameters zijn, etcetera. Misschien dat een enkele PHP-scripter dit niet snapt, maar dan vraag ik me af waarom dit voorbeeld niet in PHP is ![]() | ||||||||||||
Farenji | donderdag 24 januari 2008 @ 10:40 | |||||||||||
quote:Deze tutorial is niet voor totale leken maar voor mensen die wel een beetje kunnen scripten maar het OO denken niet onder de knie krijgen. quote:Omdat PHP een ranzige kuttaal is? | ||||||||||||
Anthraxx | donderdag 24 januari 2008 @ 10:40 | |||||||||||
Nee, Perl is lekker consistent ![]() | ||||||||||||
slacker_nl | donderdag 24 januari 2008 @ 11:18 | |||||||||||
Perl is geen ranzige kuttaal! Vieze PHP'er. | ||||||||||||
Litpho | donderdag 24 januari 2008 @ 11:19 | |||||||||||
Wellicht dat de PHP-discussie ![]() ![]() | ||||||||||||
Anthraxx | donderdag 24 januari 2008 @ 11:30 | |||||||||||
quote:PHP'er? Ik? ![]() ![]() | ||||||||||||
Farenji | donderdag 24 januari 2008 @ 11:43 | |||||||||||
Perl is mijn lievelingstaal, niet zonder reden, maar we gaan hier niet discussieren daarover. Wat ik me afvraag: moet ik hier nog tijd in steken of heeft iedereen zoiets van: "mwoa"? Want dan houd ik mijn kwaliteitscode wel lekker voor mezelf! | ||||||||||||
Farenji | donderdag 24 januari 2008 @ 20:02 | |||||||||||
Ok, dat is dan duidelijk. Stelletje php dummies. | ||||||||||||
Aaargh! | donderdag 24 januari 2008 @ 20:19 | |||||||||||
quote:Perl heeft zeker z'n toepassingen, maar om het nu een mooie taal te noemen... quote:Tja, als je echt OO wilt uitleggen dan kan je dat beter doen aan de hand van b.v. Java. Met als voordeel dat dat een taal is die echt bedoelt is om OO in te proggen en dat de syntax ook nog enigszins leesbaar is, zeker in vergelijking met die Perl meuk. | ||||||||||||
SuperRembo | vrijdag 25 januari 2008 @ 13:39 | |||||||||||
Als je OO wil uitleggen dan zou ik met een eenvoudiger voorbeeld beginnen. Ik ken Perl een beetje, maar hier zie ik door de (cryptische) string/hash/etc handling de OO niet meer. Al het gedoe als "my $classname = shift" in een "constuctor" en "my $self = shift" in een "method" sneeuwt daardoor onder. Voor dat je met die lappen code komt, had je eigenlijk moeten uitleggen hoe de objectenstructuur in gedachten hebt. Een diagrammetje erbij zou verhelderend werken. Ik vraag me af of deze structuur OO-technisch gezien wel handig in elkaar steekt. quote:Voordeel van een echt OO taal is dat alles OO is, dus zonder losse functies als join/chop/keys die natuurlijk methoden op een object horen te zijn. | ||||||||||||
Litpho | vrijdag 25 januari 2008 @ 13:43 | |||||||||||
quote:Of primitives ![]() | ||||||||||||
Anthraxx | vrijdag 25 januari 2008 @ 16:09 | |||||||||||
quote:PHP is nog triester dan Perl. | ||||||||||||
Farenji | vrijdag 25 januari 2008 @ 20:21 | |||||||||||
quote:Tja ik vrees inderdaad dat ik al te lang met perl werk - dan vergeet ik dat vreselijke geworstel dat ik in het begin had om bijv iets als references te begrijpen. Maar als ik helemaal onderaan begonnen met uitleggen was dan had ik 10 keer zoveel ruimte nodig gehad. Dan verwijs ik liever naar Leer hier Perl quote:Dit is het objectmodel: ![]() Pijlen met stippellijnen zijn dependencies, pijlen met ononderbroken lijnen is inheritance. Eigenlijk is er niet echte dependency tussen de Artist, Song en Album, want alle objecten worden in de superclass gecreeerd dmv een factory pattern. Het datamodel was niet helemaal goed doordacht want het is een database voor verzamelalbums geworden. De relaties tussen de verschillende objecten zijn gedefinieerd dmv generieke getChildren en getParent functies in DataRow. De functies in de subclasses zijn gewoon wrappers hieromheen, bijv in Artist.pm cq Song.pm:
Of nog een mooi onleesbaar staaltje van perl magic, in Artist.pm:
Het resultaat van deze functies is dus een array met Song objecten, respectievelijk een Album object. quote:Niks mis met null termininated literals. | ||||||||||||
super-muffin | vrijdag 25 januari 2008 @ 20:43 | |||||||||||
Jammer dat dit forum geen syntax highlighting heeft voor Perl. Zou het een stuk duidelijker zijn. ![]() | ||||||||||||
Aaargh! | vrijdag 25 januari 2008 @ 21:22 | |||||||||||
Die meuk is gewoon onleesbaar, zeker voor iemand die niks van OO weet. Ik bedoel, ik ben software engineer, ik droom zo ongeveer in OO, ik doe de hele dag niets anders dan proggen, 40+ uur per week, en ik moet nog ff heel goed kijken om die Perl meuk te ontcijferen. Hoe denk je dat dit op een beginner overkomt ? Die werpt een blik op die code en geeft 't onmiddelijk op. Ik denk dat de configuratie file van Sendmail nog duidelijker is dan het gemiddelde Perl script. Dit gaat nooit duidelijk zijn voor een beginner, kies alsjeblieft een duidelijkere taal als je dit wilt uitleggen. |