[oop] meningen... wat is goed?
topic vandaag heeft mij aan het denken gezet over OOP.
Ik wil graag jullie MENINGEN horen! Dus iedereen die iets doet met OOP, reageer alsjeblieft even.
Stel dat we een class hebben die een auto in elkaar zet. Laten we het simpel houden. Deze class zoekt op basis van het opgegeven model de juiste autobanden, de juiste motor, de juiste carrosserie en het juiste interieur (dashboard, stoelen, bekleding) en installeert en configureert deze zaken vervolgens. Nogmaals, het is even een heel simpel voorbeeld. Het gaat vooral om de gedachte. In mijn vorige topic zei Wouter dat je de methoden in een class gescheiden moet houden van de constructor. En daar kan ik zeker wel inkomen. Je zou dan het volgende krijgen:
Voila, we hebben een Peugeot 307 gefabriceerd!
Nu komt de vraag... een auto wordt altijd op dezelfde manier gebouwd met behulp van de bovenstaande 4 functies. Aangezien deze functies altijd moeten worden uitgevoerd om een auto te maken, is mijn vraag de volgende.
Vinden jullie (de OOP gebruikers) het een goed idee om de 4 functies vanuit de constructor aan te roepen. Dan zou je om een Peugeot 307 te maken alleen nog maar dit hoeven te doen:
En de Peugeot 307 is klaar.
De 4 functies zouden we private kunnen maken, zodat we deze niet van buitenaf kunnen aanroepen. De complete auto wordt dus gemaakt door enkel het model mee te geven aan de constructor.
Graag reacties... wel of geen goed idee? En waarom wel of niet?
Ik ben erachter dat in de OOP wereld er veel sprake is van persoonlijke voorkeur. Dat is niet erg, ik ben gewoon benieuwd naar jullie meningen. Dus wat zouden jullie doen. De functies handmatig aanroepen, of triggeren vanuit de constructor?
Een eerder Ik wil graag jullie MENINGEN horen! Dus iedereen die iets doet met OOP, reageer alsjeblieft even.
Stel dat we een class hebben die een auto in elkaar zet. Laten we het simpel houden. Deze class zoekt op basis van het opgegeven model de juiste autobanden, de juiste motor, de juiste carrosserie en het juiste interieur (dashboard, stoelen, bekleding) en installeert en configureert deze zaken vervolgens. Nogmaals, het is even een heel simpel voorbeeld. Het gaat vooral om de gedachte. In mijn vorige topic zei Wouter dat je de methoden in een class gescheiden moet houden van de constructor. En daar kan ik zeker wel inkomen. Je zou dan het volgende krijgen:
Code (php)
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
<?php
$model = 307; // we gaan een Peugeot 307 maken
$auto = new Auto($model);
$auto->zoekEnInstalleerBanden();
$auto->zoekEnInstalleerMotor();
$auto->zoekEnInstalleerCarrosserie();
$auto->zoekEnInstalleerInterieur();
?>
$model = 307; // we gaan een Peugeot 307 maken
$auto = new Auto($model);
$auto->zoekEnInstalleerBanden();
$auto->zoekEnInstalleerMotor();
$auto->zoekEnInstalleerCarrosserie();
$auto->zoekEnInstalleerInterieur();
?>
Voila, we hebben een Peugeot 307 gefabriceerd!
Nu komt de vraag... een auto wordt altijd op dezelfde manier gebouwd met behulp van de bovenstaande 4 functies. Aangezien deze functies altijd moeten worden uitgevoerd om een auto te maken, is mijn vraag de volgende.
Vinden jullie (de OOP gebruikers) het een goed idee om de 4 functies vanuit de constructor aan te roepen. Dan zou je om een Peugeot 307 te maken alleen nog maar dit hoeven te doen:
En de Peugeot 307 is klaar.
De 4 functies zouden we private kunnen maken, zodat we deze niet van buitenaf kunnen aanroepen. De complete auto wordt dus gemaakt door enkel het model mee te geven aan de constructor.
Graag reacties... wel of geen goed idee? En waarom wel of niet?
Ik ben erachter dat in de OOP wereld er veel sprake is van persoonlijke voorkeur. Dat is niet erg, ik ben gewoon benieuwd naar jullie meningen. Dus wat zouden jullie doen. De functies handmatig aanroepen, of triggeren vanuit de constructor?
En deze Peugot 307 krijgt nu misschien een simpel motortje, maar wat als ik straks een klant krijg die er een V8 in wilt hebben? Moet ik dan speciaal voor die klant een nieuwe klasse maken met een V8 motor erin?
We gaan nog even verder, er komt een klant aan in mijn winkel en die klant lijkt toevallig bij Pirelli te werken. Die hoeft echt geen banden onder zijn auto, die regelt hij zelf wel. Dan verdwijnt er dus een stap. Moet ik dan een totaal nieuwe klasse, AutoForPirelliGuy, maken?
En we fantaseren door, Peugot heeft een nieuwe auto ontwikkeld die geen motor meer heeft. Hij beweegt volledig door het magnetisch veld van de weg. Hierdoor moeten we een nieuwe carrosserie hebben en kan de motor helemaal weg. Weer een nieuwe stap maken?
Gewijzigd op 08/04/2013 14:58:06 door Wouter J
Dit zijn precies de soort voorbeelden waar ik naar op zoek ben, want dat zet mij ook weer aan het denken. En je hebt hier zeker een punt.
Dan kom ik ook gelijk weer met wat tegenargumenten :)
Stel we geven in de constructor mee wat er moet worden geinstalleerd?
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
<?php
public function __construct($model, $banden = true, $motor = true, $carrosserie = true, $interieur = true) {
}
?>
public function __construct($model, $banden = true, $motor = true, $carrosserie = true, $interieur = true) {
}
?>
Voor de Pirelli guy die geen banden wil doen we nu dit:
Code (php)
1
2
3
4
5
6
2
3
4
5
6
<?php
$model = 307;
$auto = new Auto($model, false); // de auto krijgt alle opties behalve banden
?>
$model = 307;
$auto = new Auto($model, false); // de auto krijgt alle opties behalve banden
?>
Ik snap dat dit misschien een beetje een flauwe oplossing is, maar het is wel goed om een besef te krijgen waarom je bepaalde dingen wel of niet zou moeten doen.
Dus... jij bent weer aan zet. Waarom zou jij dus dit doen (voor de Pirelli guy):
Code (php)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
<?php
$model = 307;
$auto = new Auto($model);
$auto->zoekEnInstalleerMotor();
$auto->zoekEnInstalleerCarrosserie();
$auto->zoekEnInstalleerInterieur();
?>
$model = 307;
$auto = new Auto($model);
$auto->zoekEnInstalleerMotor();
$auto->zoekEnInstalleerCarrosserie();
$auto->zoekEnInstalleerInterieur();
?>
en niet dit...
Pirelli guy is 1 van die 3 voorbeeldjes, probeer nu met jouw code de andere 2 goed werkend te krijgen?
$auto = new Auto($model,false,false,false,false);
Dit ziet er natuurlijk ook niet uit.
Het ding weet niets, en is afhankelijk van het gene wat hij gebruikt.
Oftewel, het is een blauwdruk van.
Dus waarom zou je dan een constructor gebruiken om die dingen te zetten?
Als meneer geen standaard banden wenst, kan je ze beter setten denk ik.
Nou stel dus... we hebben een auto zonder motor. Deze Auto class is dusdanig intelligent dat hij aan de hand van het model kan bepalen hoe de auto geassembleerd moet worden. Bij de auto zonder motor weet hij dus dat er geen motor wordt geplaatst.
Wat betreft de V8 motor... die past niet (we gaan er in het voorbeeld vanuit dat er maar 1 passende motor is).
Om de vraag dus wat breder te trekken... de class is zelf in staat om een auto te maken. Hij heeft zelf al die intelligentie in huis. Waarom zouden we dan nog handmatig al die functies gaan aanroepen? Dat is eigenlijk in essentie mijn vraag.
Oké... een heel ander voorbeeld. Stel we hebben een attractie in een pretpark, bijv. een spookhuis. Bij dat spookhuis is een "machinist" haha, hoe noem je zo iemand? Nou ja, in ieder geval iemand die de knoppen bedient. Hij doet de volgende handelingen:
1) Druk op knop A: er gaat een deur open en de bezoekers kunnen naar binnen in de wachtruimte
2) Precies 30 seconden later, druk op knop B: het licht in de wachtruimte gaat uit en de bezoekers zien niks meer
3) Druk op knop C: er worden bliksemschichten afgevuurd
4) Druk op knop D: er komt een treintje aangereden en de bezoekers in de wachtruimte moeten instappen
5) Druk op knop E: de vergrendeling aan de zijkant sluit
6) Druk op knop F: treintje gaat rijden.
7) Druk op knop A: de deur van de wachtruimte gaat weer open en nieuwe bezoekers kunnen naar binnen
8) Druk op knop G: het rijdende treintje wordt stopgezet op een hoog punt
9) Druk op knop H: het stopgezette treintje raast met hoge snelheid naar beneden
10) Druk op knop I: afremmen van treintje
11) Druk op knop J: treintje stopt
12) Druk op knop K: vergrendeling opent en bezoekers stappen weer uit
Dit gaat zo de hele dag door. De uitgevoerde stappen zijn telkens hetzelfde.
Nu de vraag, waarom niet alleen 1 knop Start en de rest gaat vanzelf?
Gewijzigd op 08/04/2013 15:31:07 door Ozzie PHP
Stel het deurtje sluit te vroeg en er zit iemand tussen?
Treintje gaat rijden en de mensen zijn nog niet allemaal ingestapt?
Daarom zitten er meestal meerdere knopjes en controle op. ;)
Gewijzigd op 08/04/2013 15:40:15 door Bart V B
We hebben een class met 3 methods die altijd na elkaar moeten worden uitgevoerd. Als volgt:
Waarom dan niet een constructor maken die deze 3 methods aanroept, zodat je zelf nog alleen maar dit hoeft te doen:
Gewijzigd op 08/04/2013 15:41:34 door Ozzie PHP
Quote:
Om de vraag dus wat breder te trekken... de class is zelf in staat om een auto te maken. Hij heeft zelf al die intelligentie in huis. Waarom zouden we dan nog handmatig al die functies gaan aanroepen? Dat is eigenlijk in essentie mijn vraag.
Dus jij gaat voor elke mogelijke combinatie van een merk (want een Peugot 307 kan meerdere versies hebben, bijv. de sport versie of de stad versie) de klasse weer vullen? Als Peugot een nieuwe auto uitbrengt vul je die hele klasse weer? Je mag er niet zomaar van uitgaan dat 'de klasse intelligent is', de klasse kan niks jij moet hem intelligent maken. En dan komen we bij een basis principe van OO: Isoleer wat verandert
Het geen wat veranderd (hoe een auto in elkaar zit) mag niet in een klasse zitten die vast staat.
Quote:
Nu de vraag, waarom niet alleen 1 knop Start en de rest gaat vanzelf?
Goed nu gaan we heel erg afwijken van het programmeren. Je probeert nu code als real-life dingen te zien, dat is natuurlijk niet waar.
Probeer dus eerst een meer real-use-case scenario te bedenken voor je volgende reactie.
Quote:
Waarom dan niet een constructor maken die deze 3 methods aanroept, zodat je zelf nog alleen maar dit hoeft te doen:
Dat is natuurlijk veel te vaag. OO is niet in elk scenario hetzelfde. Je moet je dus eerst een preciezer voorbeeld geven en dan zul je zien dat er altijd een goede rede is om ze apart aan te roepen.
Jij gaat je voorbeelden steeds vager maken, zodat we je op gegeven moment gelijk moeten geven. Als dat echt zo is dan is er dus 1 conclusie: Jouw techniek is verkeerd, omdat blijkt dat in real-case-scenario's er iets mis is.
Gewijzigd op 08/04/2013 15:46:08 door Wouter J
Wouter J op 08/04/2013 15:43:39:
Dus jij gaat voor elke mogelijke combinatie van een merk (want een Peugot 307 kan meerdere versies hebben, bijv. de sport versie of de stad versie) de klasse weer vullen? Als Peugot een nieuwe auto uitbrengt vul je die hele klasse weer?
Ik denk dus bijv. aan een config bestand:
Code (php)
1
2
3
4
5
2
3
4
5
307:
banden: pirelli 307
motor: 34as-AD130PK
carosserie: peugeot default
interieur: leer
banden: pirelli 307
motor: 34as-AD130PK
carosserie: peugeot default
interieur: leer
Wouter J op 08/04/2013 15:43:39:
En dan komen we bij een basis principe van OO: Isoleer wat verandert
Maar als het in een config bestand staat, staat het buiten de class.
Wouter J op 08/04/2013 15:43:39:
Goed nu gaan we heel erg afwijken van het programmeren. Je probeert nu code als real-life dingen te zien, dat is natuurlijk niet waar.
Het is misschien niet waar, maar daardoor niet minder waar :-) De vraag is... als iets een vaste routine heeft, waarom zou je dan die routine telkens handmatig aanroepen?Quote:
Nu de vraag, waarom niet alleen 1 knop Start en de rest gaat vanzelf?
Goed nu gaan we heel erg afwijken van het programmeren. Je probeert nu code als real-life dingen te zien, dat is natuurlijk niet waar.
Stel we hebben een verwarmings class. Door die class aan te roepen kan ik de verwarming in een huis aanzetten.
We zouden dit kunnen doen:
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
<?php
$verwarming = new Verwarming();
$verwarming->controleerWaterToevoer();
$verwarming->controleerWaterNiveauInBoiler();
$verwarming->controleerOfGeiserAanstaat();
$verwarming->stelTemperatuurIn(21); // 21 graden
?>
$verwarming = new Verwarming();
$verwarming->controleerWaterToevoer();
$verwarming->controleerWaterNiveauInBoiler();
$verwarming->controleerOfGeiserAanstaat();
$verwarming->stelTemperatuurIn(21); // 21 graden
?>
Maar we zouden ook dit kunnen doen:
Snap je wat ik bedoel?
Gewijzigd op 08/04/2013 15:55:53 door Ozzie PHP
Is iets anders dan de verwarming aanzetten. In dit geval is het namelijk de verwarming installeren.
Vervolgens gebruiken we bijv. een method Verwarming#setTemperature(21) om de verwarming in te stellen. En deze roept al deze 4 methods aan. Natuurlijk ga je die in dit geval niet allemaal zelf aanroepen, wat je natuurlijk ook niet gaat doen is telkens een nieuwe verwarming installeren als je de temperatuur hoger of lager wilt zetten.
In je stelTemperatuurIn methode kan je die controles dan beter doen.
De situatie zoals ik die schets zal ook niet vaak voorkomen, maar als ie dus voorkomt wat moet ik er dan mee.
Even terugkomend op het voorbeeld van de autoloader... ik heb dus een register functie die altijd moet worden aangeroepen om de class te laten werken. Dus zodoende vroeg ik me af waarom ik 'm dan niet in de constructor zou aanroepen.
Stel bijv. dat je bij die verwarmingsclass altijd (voordat je de verwarming gaat installeren) zou willen controleren of er wel een leidingstelsel aanwezig is in het betreffende pand, waarom zou je die controle dan niet in de constructor uitvoeren in plaats van:
$verwarming = new Verwarming();
$verwarming->checkLeidingStelsel();
Ozzie PHP op 08/04/2013 16:06:15:
Een autoloader is om verschillende redenen een uitzondering. Autoloaders worden aangeroepen in de volgorde waarin je ze op een stack plaatst. Dat betekent dat je het registreren van de ene autoloader niet los kunt zien van het registreren van een andere autoloader. Wil je daarover wel controle houden, dan zou je het registreren bijvoorbeeld kunnen verplaatsen naar één centrale Registry waar alle autoloaders zich moeten "aanmelden".Even terugkomend op het voorbeeld van de autoloader... ik heb dus een register functie die altijd moet worden aangeroepen om de class te laten werken. Dus zodoende vroeg ik me af waarom ik 'm dan niet in de constructor zou aanroepen.
Ozzie PHP op 08/04/2013 16:06:15:
Stel bijv. dat je bij die verwarmingsclass altijd (voordat je de verwarming gaat installeren) zou willen controleren of er wel een leidingstelsel aanwezig is in het betreffende pand, waarom zou je die controle dan niet in de constructor uitvoeren in plaats van:
$verwarming = new Verwarming();
$verwarming->checkLeidingStelsel();
$verwarming = new Verwarming();
$verwarming->checkLeidingStelsel();
De verwarming "weet" niet dat ze is aangesloten op een leidingstelsel. En al helemaal niet dat dit leidingstelsel zich in een pand bevindt. Sterker nog, de verwarming weet niet eens wat een leiding of een pand is.
Een controle uitvoeren is iets anders dan totale controle willen hebben. De verwarming hoeft alleen een fout te constateren (ik voel te weinig waterdruk op mijn drukmeter) en die te melden (ik doe het derde ledje van links aan). Daarna is het aan de eigenaar van de verwarming om iets te doen met de rode ledjes.
Gewijzigd op 09/04/2013 08:17:30 door Ward van der Put
Ozzie.. wat probeer je nu eigenlijk te doen? Een auto inladen met de juiste properties? Dan maak je beter gebruik van een factory.