[oop] constructor als "uitvoerder"?

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Pagina: « vorige 1 2 3 volgende »

Wouter J

Wouter J

18/05/2014 21:46:57
Quote Anchor link
>> Dat je dan net zo goed die execute method kunt aanroepen vanuit de constructor?


Nee, want de constructor is voor constructie. Als je een huis bouwt dan weet je dat er mensen in gaan wonen. Dat hoeft nog niet te betekenen dat de arbeiders meteen erin moeten gaan wonen... Toch gaat het bij elke bouw hetzelfde: Constructor maakt huis; makelaar zoekt bewoner; bewoner woont in huis.
 
PHP hulp

PHP hulp

28/04/2024 01:09:45
 
Ozzie PHP

Ozzie PHP

18/05/2014 22:12:34
Quote Anchor link
Ik vind het nu wel wat lastig. Ik pak even de eerdere uitspraken van Ward erbij.

Het gaat in deze specifieke situatie om het toevoegen van paden aan een object. Niet helemaal hetzelfde, maar het gaat even om wat Ward hierover zegt:

Ward van der Put op 24/10/2013 08:58:11:
Kun je iets nuttigs doen na new Paths() zonder de methode Paths::add() te gebruiken? Is het antwoord "Nee", dan hoort add() bij het initialisatieproces en zou ik een constructor gebruiken die drie prototypen ondersteunt en de keuze overlaat aan de gebruikers van de klasse:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
// Duidelijk gestructureerd en overzichtelijk.
$paths = new Paths();
$paths->add($paths_data1);
$paths->add($paths_data2);

// Dit is heel logisch ...
$paths = new Paths($paths_data1);
$paths->add($paths_data2);

// ... als dit ook wordt ondersteund.
$paths = new Paths($paths_data);
?>

Vervolgens reageer ik daar als volgt op:

Ozzie PHP op 24/10/2013 09:07:46:
Het adden van de paden is in mijn ogen geen wezenlijk onderdeel van het "gebruiksklaar" maken van de class. Want als ik gewoon dit doe:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
$paths
= new Paths();
?>

... dan werkt de class prima, en kan ik gewoon gebruik maken van de add() method. En daarom denk ik dus dat het toevoegen van paden niet thuishoort in de constructor. Ben je het daar mee eens, of niet?

En Ward weer:

Ward van der Put op 24/10/2013 09:17:37:
Ja en nee. De uiterste consequentie van deze argumentatie is namelijk dat je helemaal nooit een constructor nodig hebt: je kunt immers altijd alles naar methoden delegeren.

Als je na new Paths() slechts een lege huls hebt en je meestal pas na add() iets zinvols kunt doen, dan zou ik de constructor inzetten.

Ben jij het dan niet eens met wat Ward hier zegt?
 
Wouter J

Wouter J

18/05/2014 22:18:03
Quote Anchor link
Een constructor maakt het object klaar voor gebruik. Zoals ward zegt, als je na de constructor een object hebt waarmee je niks kan voordat je een bepaalde method hebt uitgevoerd doe je wat verkeerd.

Dat is hier echter helemaal niet het geval. Je kan perfect het object gebruiken zonder de request af te handelen.
 
Ozzie PHP

Ozzie PHP

18/05/2014 22:42:47
Quote Anchor link
Kun je dat toelichten Wouter? Het enige wat die class doet is het request afhandelen. Hij doet niks anders.... stel dat ik de execute method public maak, dan is het ook de enige method die ik kan aanroepen. Ik snap het verschil dus niet helemaal.
 
Frank Nietbelangrijk

Frank Nietbelangrijk

18/05/2014 23:05:28
Quote Anchor link
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

class Foo {

  private $foo;
 
  public function __constructor($foo, $bar) {
    $this->foo= $foo.
    $this->initializeFoo();
    $this->executeFoo();
    $this->doTheFoo();
    $this->addSomeBar($bar);
    $this->createFooBar();
  }

}


?>


Dit voorbeeld genomen Ozzie;

Het werkt, De een zegt dat het mag, de ander van niet.

Echter staat er één ding vast en dat is dat dit een ultiem voorbeeld is van inflexibiliteit. Ik wijs naar mijn eerdere opmerking dat je later niet meer om de code in de constructor heen kunt. en dat kan dus slecht uitpakken later. Dan wil je die constructor alsnog gaan verbouwen en loopt je eerder geschreven code in de soep.
 
Reshad F

Reshad F

18/05/2014 23:10:20
Quote Anchor link
Ozzie, je moet proberen zo min mogelijk de constructor te gebruiken. Het enige waar de constructor voor gebruikt dient te worden is om bij aanmaak van het object dingen toe te wijzen. De constructor mag naar mijn mening geen commando bevatten om dingen uit te voeren dat moet je delegeren naar een methode. Jij wilt soms heel ingewikkeld denken maar soms is het gewoon heel simpel.

In jou geval is execute() een mooie methode die je public kan maken en die de taken van de constructor op zich neemt.
 
Ozzie PHP

Ozzie PHP

18/05/2014 23:22:42
Quote Anchor link
>> De constructor mag naar mijn mening geen commando bevatten om dingen uit te voeren dat moet je delegeren naar een methode.

>> In jou geval is execute() een mooie methode die je public kan maken en die de taken van de constructor op zich neemt.

Oké... maar dan heeft die hele class maar 1 method die kan worden aangeroepen. En die ene method MOET ook worden aangeroepen, anders doet de class niks. Is dat dan niet raar?

Anders gezegds, als er toch maar 1 method is die je kunt aanroepen en die MOET worden uitgevoerd, zou dat dan geen reden kunnen zijn om de method vanuit de constructor aan te roepen?
 
Wouter J

Wouter J

18/05/2014 23:31:36
Quote Anchor link
>> zou dat dan geen reden kunnen zijn om de method vanuit de constructor aan te roepen?

Nee, want een constructor is voor constructie van een object. Een method is voor de uitvoering van een object.

En "de klasse doet niks zonder die method call" is iets anders als "de klasse kan niks zonder die method call".

Ik weet niet hoe vaak ik en andere mensen dit nog in dit topic moeten plaatsen. Maak nu je keuze: "Ja, ik luister naar Dos, Frank, Reshad, Wouter, Ward" of "Nee, ik doe mijn eigen willetje". Ik respecteer beide keuzes, maar het heeft niet heel veel zin deze "ik wil het"/"nee, doe nou niet" discussie verder voort te zetten.
 
Ozzie PHP

Ozzie PHP

18/05/2014 23:34:31
Quote Anchor link
>> Ik respecteer beide keuzes, maar het heeft niet heel veel zin deze "ik wil het"/"nee, doe nou niet" discussie verder voort te zetten.

Nee, ik heb de meningen nu wel zo'n beetje op een rijtje, alhoewel het nog steeds aan mij is om de discussie door te zetten ;)

>> En "de klasse doet niks zonder die method call" is iets anders als "de klasse kan niks zonder die method call".

Daar heb je een goed punt.

Dan wordt het toch een public execute method. Bedankt allemaal voor het meedenken en de verschillende visies!
 
Ward van der Put
Moderator

Ward van der Put

19/05/2014 07:58:07
Quote Anchor link
Ozzie, mijn toelichting ging over het initialiseren van een object. Dát moet je vermijden, want dat is de taak van de constructor.

Als je altijd in twee stappen dit moet doen voordat je een bruikbare $foo hebt, dan deugt het ontwerp van de klasse niet:

$foo = new Foo();
$foo->init();

Niet altijd de betrouwbaarste bron, maar zoals Wikipedia scbrijft over constructors: “They have the task of initializing the object’s data members and of establishing the invariant of the class, failing if the invariant is invalid. A properly written constructor leaves the resulting object in a valid state.”

Als je ná $foo = new Foo(); een ongeldig object hebt en het object pas later met $foo->init(); geldig wordt, dan deugt het ontwerp dus niet: het object is tijdelijk invalid. Het mist dan bovendien een klasse-invariant (of heeft een invariant die onwaar is en van buiten de klasse waar moet worden gemaakt). Hier had je de constructor moeten gebruiken.
 
NOLot -

NOLot -

19/05/2014 10:09:25
Quote Anchor link
Als je zoals in je eerste voorbeeld laat zien een class hebt die maar 1 public methode heeft, in dit geval het afhandelen van een request, en je weet 100% zeker dat er geen extra methodes of dependencies bij komen kun je er ook een static methode van maken. e.g.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
Processor::execute($request);


Puur gezien vanuit readability van de code vind ik dat beter dan

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
new Processor($request);


Maar uiteindelijk is het natuurlijk je eigen keuze :)

Verder ben ik het er ook mee eens dat de constructor alleen maar gebruikt moet worden voor het initialiseren van het object, en eventueel valideren van de binnenkomende variablen. Stel je voor dat je Processor::execute methode een fout geeft bij het versturen van een response ($this->sendResponse()), en het enige dat ik, als externe developer die met jou code werkt, heb gedaan is een nieuw Processor object aanmaken zou ik wel even raar opkijken.
 
Ozzie PHP

Ozzie PHP

19/05/2014 13:03:48
Quote Anchor link
Bedankt voor jullie toelichtingen!

@Ward:

>> Als je altijd in twee stappen dit moet doen voordat je een bruikbare $foo hebt, dan deugt het ontwerp van de klasse niet:

Hier heb ik nog een vraagje over.

Stel dat je de Processor class hebt en het enige wat je in de constructor doet is het request setten, en verder niks. In principe is de class zelf nu dus gebruiksklaar.

Nu is de volgende stap in het proces dat je een aantal dingen wilt initialiseren, je wilt bijv. de services laden en je wilt wat gegevens inladen (bijv. paden). In feite is dit dus ook een vorm van initialiseren. Hoort dit dan ook thuis in de constructor?

@NOLot:

>> ... en je weet 100% zeker dat er geen extra methodes of dependencies bij komen kun je er ook een static methode van maken. e.g.

Waarom dan een statische methode en niet dit:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php
$processor
= new Processor($request);
$processor->execute();
?>

Wat is precies het verschil?
 
NOLot -

NOLot -

19/05/2014 13:32:06
Quote Anchor link
Bij een statische methode afhankelijk ben je afhankelijk van de variablen die meegegeven worden. Als je er een class van maakt kun je nog extra instellingen meegeven via andere methodes (zoals bijvoorbeeld het meegeven van een logger aan het object). Maar dit staat toch helemaal los van je vraag over het uitvoeren van logica in de constructor?
 
Ward van der Put
Moderator

Ward van der Put

19/05/2014 13:33:27
Quote Anchor link
>> Stel dat je de Processor class hebt en het enige wat je in de constructor doet is het request setten, en verder niks. In principe is de class zelf nu dus gebruiksklaar.

Zoals je zelf al zegt: je doet het in dit geval al in de constructor, omdat je Processor anders ongeldig is.

Dat is het doorslaggevende criterium: de constructor levert een geldig object op. De enkele aanroep van de klasse met new ... moet een valid object opleveren. Daar moet niet nog eens init() of iets dergelijks voor initialiseren of een andere vorm van het "booten" of "opstarten" van het object overheen.

>> Nu is de volgende stap in het proces dat je een aantal dingen wilt initialiseren, je wilt bijv. de services laden en je wilt wat gegevens inladen (bijv. paden). In feite is dit dus ook een vorm van initialiseren. Hoort dit dan ook thuis in de constructor?

Dat klinkt als een verzameling van verschillende taken en verschillende verantwoordelijkheden — en dus verschillende klassen. Maar dit is strikt genomen meer configureren dan initialiseren.

Even een voorbeeldje met een databaseverbinding. Die open je liever zó:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
$dbh
= new Database($servername, $username, $password);
?>


dan zo:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php
$dbh
= new Database();
$dbh->setServerByName($servername);
$dbh->setUserName($username);
$dbh->setPassword($password);
$dbh->connect();
?>


Het kán wel op de tweede manier — en incidenteel heb je het misschien zelfs per se nodig — maar fraai is anders.
 
Ozzie PHP

Ozzie PHP

19/05/2014 13:45:10
Quote Anchor link
>> Bij een statische methode afhankelijk ben je afhankelijk van de variablen die meegegeven worden. Als je er een class van maakt kun je nog extra instellingen meegeven via andere methodes (zoals bijvoorbeeld het meegeven van een logger aan het object). Maar dit staat toch helemaal los van je vraag over het uitvoeren van logica in de constructor?

Ik snap het nog steeds niet (sorry). Mijn vraag was of de constructor logica mag uitvoeren. Het antwoord daarop is nee. Oké prima. Maar dan moet er dus wel een execute method worden aangeroepen van buitenaf. Toen zei jij dat je dat dan met een statische methode zou doen:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
Processor::execute($request);
?>

Op zich vind ik dat wel mooi om op deze manier te doen, maar mijn vraag is waarom je voor een statische methode kiest in plaats van dit:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php
$processor
= new Processor($request);
$processor->execute();
?>

Misschien moet ik de vraag iets anders stellen. Wanneer kies je voor een statische aanroep?

@Ward:

>> Dat klinkt als een verzameling van verschillende taken en verschillende verantwoordelijkheden — en dus verschillende klassen. Maar dit is strikt genomen meer configureren dan initialiseren.

Klopt, het wordt ook door verschillende classes uitgevoerd, maar het moet vanuit de processor worden getriggerd. Deze handelingen moeten gebeuren voordat de execute method wordt aangeroepen. Dus dan kan ik het vanuit de constructor doen... maar dan doet de constructor dus eigenlijk te veel, of ik ga de functie handmatig aanroepen, maar dan krijg je dus weer een extra init() aanroep en dat wilden we ook niet. Het enige dat dan overblijft, is dat de execute method die handelingen gaat uitvoeren/triggeren. Ik denk dat dat dan de beste oplossing is.
 
NOLot -

NOLot -

19/05/2014 13:56:19
Quote Anchor link
Ozzie PHP op 19/05/2014 13:45:10:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
Processor::execute($request);
?>

Op zich vind ik dat wel mooi om op deze manier te doen, maar mijn vraag is waarom je voor een statische methode kiest in plaats van dit:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php
$processor
= new Processor($request);
$processor->execute();
?>



Ik keek naar je gegeven voorbeeld, je hebt een class die 1 variable krijgt ($request) en maar 1 ding doet (execute). Geen extra dependencies of whatsoever. Maar goed hierover verschillen de meningen. Er is geen één manier binnen het programmeren, en ik zou gaan wat voor jezelf het duidelijkst is
 
Ozzie PHP

Ozzie PHP

19/05/2014 14:09:59
Quote Anchor link
@NOLot:

Ik vind de oplossing die jij aandraagt wel een mooie. In één regel is duidelijk wat er gebeurt. Ik denk dus dat ik het op deze manier ga doen.

Maar zo'n oplossing gebruik je dus als een class maar 1 ding kan doen (1 method heef) en verder geen dependencies heeft. Correct?
 
NOLot -

NOLot -

19/05/2014 14:14:03
Quote Anchor link
Zo'n oplossing gebruik ik wanneer ik er zin in heb :D Maar vooral voor dat soort situatie's inderdaad
 
Ozzie PHP

Ozzie PHP

19/05/2014 14:15:31
Quote Anchor link
>> Zo'n oplossing gebruik ik wanneer ik er zin in heb :D

Lol... :)
 
Ward van der Put
Moderator

Ward van der Put

19/05/2014 14:42:52
Quote Anchor link
Ozzie PHP op 19/05/2014 14:09:59:
Maar zo'n oplossing gebruik je dus als een class maar 1 ding kan doen (1 method heef) en verder geen dependencies heeft. Correct?

Die dependencies zijn nu juist een deel van het probleem: je hebt een kernelprocessor met afhankelijkheden die dóór die afhankelijkheden eerst moet worden geconfigureerd voordat deze kan worden geïnitialiseerd :-)

Dependencies zijn ook een deel van de oplossing, want je kunt de drie verantwoordelijkheden instellen/controleren/uitvoeren ook splitsen, bijvoorbeeld in:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php
class Processor
{
    public static function execute(ProcessorRequest $request)
    {

        if (true === ProcessorRequestValidator::isValid($request)) {
            // ...
        }
    }
}

?>
 

Pagina: « vorige 1 2 3 volgende »



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.