[PHP/OOP] - Class zelf zijn extended class laten kiezen

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • gvanh
  • Registratie: April 2003
  • Laatst online: 02-12-2023

gvanh

Webdeveloper

Topicstarter
Hallo,

Mijn vraag heb ik nog niet helder voor ogen, en misschien is het wel een onzin-vraag, maar toch even kijken hoe en wat. De kwestie heeft betrekking op classes die worden 'extend' door een andere class. Waar het in het kort op neerkomt, is dat ik een class, afhankelijk van een setting die hij mee krijgt, wil laten kiezen van welke 'extended' class hij een object wordt. En dat dan zonder te werken met een factory method.

Het komt dus neer op zoiets als dit:
PHP:
1
2
3
4
5
6
7
8
9
10
11
class Sedan extends Car { }
class Convertible extends Car { }
class Car {
  public function __construct($type) {
    if ( $type == 'sedan' ) {
      $this = new Sedan();
    } elseif ( $type == 'convertible' ) {
      $this = new Convertible();
    }
  }
}


Kan zoiets? Of is het sowieso onzin en is hier een beter alternatief voor?
Overigens zou ik het liefst nog zelfs op een later moment (dus nadat het Car object al gemaakt is) het object nog willen 'transformeren' naar een instance van één van de specifieke classes.

Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Als de aanroepende code het $type al weet, kan de aanroepende code toch net zo goed meteen new $type doen? :?

{signature}


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Als je compile-time ( of parse-time in geval van PHP ) nog niet weet van welke class je extend is het toch niet echt nuttig om dat te veranderen :?

Je zou eventueel kunnen denken aan composition. Je geeft dan een instance van een class mee ( die een interface implementeerd ), door middel van configuratie zou je dan het type kunnen bepalen.

In het geval van je Car example, zou je bijvoorbeeld een Engine mee kunnen geven, en aan de hand van de configuratie kan je dan een TurboEngine of HybridEngine meegeven. Aangezien beide classes dezelfde interface hebben, hoef je in je Car geen rekening te houden wat voor Engine je hebt.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Je code is onzin. Het druist in tegen het principe dat een class niet ineens een andere class wordt (hij kan op sommige plekken alleen als een andere class gebruikt worden). Waar je waarschijnlijk naar op zoek bent is het factory pattern.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • gvanh
  • Registratie: April 2003
  • Laatst online: 02-12-2023

gvanh

Webdeveloper

Topicstarter
Voutloos schreef op donderdag 19 maart 2009 @ 10:12:
Als de aanroepende code het $type al weet, kan de aanroepende code toch net zo goed meteen new $type doen? :?
Mijn voorbeeld was bedoeld als zeer versimpelde weergave van de werkelijkheid.
Je code is onzin. Het druist in tegen het principe dat een class niet ineens een andere class wordt (hij kan op sommige plekken alleen als een andere class gebruikt worden). Waar je waarschijnlijk naar op zoek bent is het factory pattern.
Is dat werkelijk een vaststaand OOP-principe? Wist ik niet.

Om een illustratie te geven van de situatie waarop dit van toepassing is. Het gaat om een FormHandler die in verschillende stappen een formulier kan afhandelen. Hierbij wordt een XML-bestand gebruikt als "template" voor het formulier en de verschillende stappen daarin. De laatste stap van het formulier is er één die afwijkt van alle voorgaande stappen, omdat in deze stap een "samenvatting" gegeven moet worden van alle data die in voorgaande stappen is gegeven.

Op dit moment is er één class die de hele boel afhandelt. Deze class bepaalt zelf ook (n.a.v. controle van user-input) welke stap van het proces getoond moet worden. In de laatste stap wordt nu een hoop ge-if-then-else-t. Het zou prettiger zijn om dezelfde parse method te kunnen gebruiken, maar dan in een andere implementatie van dezelfde class. Maar pas op het moment dat de user-input gecontroleerd is, kan deze "beslissing" worden genomen. Op die manier kwam ik - al redenerend - op mijn schets hierboven.

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

gvanh schreef op donderdag 19 maart 2009 @ 11:14:
Is dat werkelijk een vaststaand OOP-principe? Wist ik niet.
Weer wat geleerd dus ;)..

Het punt is, wanneer je "new Car()" doet, dan maak je dus een Car. Niet een Sedan, niet een Object, maar een Car. Het hele inherit principe komt pas om de hoek kijken wanneer de class al gemaakt is. Wanneer je een Sedan hebt, dan kun je die op de plekken gebruiken waar je een Sedan verwacht, waar je een Car verwacht of waar je een Object verwacht. Wat niet kan is dat je een Car object kunt gebruiken op plekken waar je een Sedan verwacht.


Om nog even terug te komen op je usecase. Toevallig ben ik met exact hetzelfde bezig. Ik gebruik echter niet 1 Class, maar een stuk meer. Ik heb een class wizard die de methode start, terug, verder en afhandelen heeft. De wizard heeft vervolgens een lijst met steps. Elke step handelt alles wat bij die step hoort af (validatie, maar ook ajax onderdelen ed).

Of je er veel aan hebt weet ik niet. Mijn ontwerp is voor een JSF applicatie. De manier van implementeren is nogal anders ivm php.

[ Voor 27% gewijzigd door Janoz op 19-03-2009 11:32 ]

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

gvanh schreef op donderdag 19 maart 2009 @ 11:14:
[...]

Is dat werkelijk een vaststaand OOP-principe? Wist ik niet.
Waarom geef je in je startpost aan dat je geen factory wil gebruiken als je blijkbaar niet helemaal weet wat het is? :o

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • gvanh
  • Registratie: April 2003
  • Laatst online: 02-12-2023

gvanh

Webdeveloper

Topicstarter
Om nog even terug te komen op je usecase. Toevallig ben ik met exact hetzelfde bezig.
Geestig. Mijn class heb ik een paar weken geleden gemaakt en inmiddels al voor een aantal websites met succes ingezet. Ik ben alleen nog niet helemaal blij met de leesbaarheid en maintainability. Vandaar dat ik nu bezig ben met een refactoring-slag. Ook omdat ik deze methode in een wat andere context wil kunnen inzetten. Het leuke van het feit dat de onderliggende "configuratie" van formulieren vastligt in XML, is het dus mogelijk om de formulieren volledig te laten afwijken per website of applicatie. In dat opzicht ligt dus eigenlijk niets vast, noch het aantal stappen, noch de verplichte velden of de manier van afhandeling (AJAX of "standaard" HTML).

Dezelfde class wil ik nu ook kunnen gebruiken voor diverse losse formulieren in een applicatie die ik aan het uitbreiden ben, en waarbij dus ook gegevens vooraf ingeladen worden.

Acties:
  • 0 Henk 'm!

  • gvanh
  • Registratie: April 2003
  • Laatst online: 02-12-2023

gvanh

Webdeveloper

Topicstarter
Waarom geef je in je startpost aan dat je geen factory wil gebruiken als je blijkbaar niet helemaal weet wat het is?
Ik weet prima wat een factory is, alleen gebruik je een factory ook weer op het moment dat je vooraf bepaalt wat voor specifieke class je wilt gebruiken. De crux is hier nu juist dat ik "gaandeweg" mijn instance wil aanpassen aan wat er gebeurt tijdens de afhandeling van user-input.

Acties:
  • 0 Henk 'm!

  • Jaap-Jan
  • Registratie: Februari 2001
  • Laatst online: 15:06
Je wilt dus behavior aanpassen @runtime. Waar je dan naar op zoek bent is het Strategy pattern.

| Last.fm | "Mr Bent liked counting. You could trust numbers, except perhaps for pi, but he was working on that in his spare time and it was bound to give in sooner or later." -Terry Pratchett


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
gvanh schreef op donderdag 19 maart 2009 @ 11:46:
[...]


Ik weet prima wat een factory is, alleen gebruik je een factory ook weer op het moment dat je vooraf bepaalt wat voor specifieke class je wilt gebruiken. De crux is hier nu juist dat ik "gaandeweg" mijn instance wil aanpassen aan wat er gebeurt tijdens de afhandeling van user-input.
Dan ga je dus composition gebruiken. Als je van te voren niet weet wat je class precies allemaal gaat doen, dan moet je niet je class zelf gaan veranderen, maar zijn onderdelen. Een beetje zoals Janoz voorsteld lijkt mij het flexibelst

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Class Wizard
{
      List Steps;
      Step CurrenStep;

      AddStep( Step );
      Remove( Step );

      Next();
      Previous();
      Finish();
}
class Step
{
     Render();
     Validate();
}

MyWizardConfigurator
{
     Create()
     {
            LeesXml();
            Wizard wiz = new Wizard();
            Foreach(Step in XmlFile)
            {
                   wiz.Add( new Step from XmlNode );
            }
     }
}

En dan heb je natuurlijk meer impelementaties van Step, die verschillende soorten steps implementeren.

[ Voor 4% gewijzigd door Woy op 19-03-2009 12:04 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
Gaandeweg veranderen betekent het veranderen van de *state* van een object, niet van z'n class.

Het probleem zit hier in je modellering: Sedan is helemaal geen subclass van Car, maar van BodyType (carrosserie). Een Car HAS-A (en dus niet IS-A) BodyType. Op die manier kun je prima je Car configureren met een andere BodyType zonder dat je class van de Car hoeft te veranderen.

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

Verwijderd

En kom je dus, zoals Jaap-Jan al zegt, op een Strategy pattern terecht.

Acties:
  • 0 Henk 'm!

  • gvanh
  • Registratie: April 2003
  • Laatst online: 02-12-2023

gvanh

Webdeveloper

Topicstarter
Veel dank voor jullie reacties tot zover ... ik ga met de suggesties aan de slag en ga kijken wat de handigste insteek is.

Acties:
  • 0 Henk 'm!

Verwijderd

Verwijderd schreef op donderdag 19 maart 2009 @ 12:01:
En kom je dus, zoals Jaap-Jan al zegt, op een Strategy pattern terecht.
Ik ben het hier niet helemaal mee eens. Strategy is vooral handig als je @runtime algorithmes wilt veranderen, maar niet de data-set die je gebruikt. Handig als je bijv. van te voren niet weet hoe veel je data je hebt en @runtime een algoritme wilt kiezen wat efficienter met veel data om kan gaan, maar te lomp/overkill is voor een kleine set.

Wat betreft het Auto - Sedan/Convertible verhaal, ik zou dan eerder denken aan een State pattern. Hier mee kun je het objecttype @runtime veranderen, ipv de operaties/algoritmes die je er op uit voert.

Ook zou ik het type Sedan afleiden van Auto, en Convertible evt. van Sedan (geen verstand van auto's btw) of evt je Sedan uitbreiden dmv Decorators. Een en ander is natuurlijk wel afhankelijk van wat je er uiteindelijk mee wilt en wat voor jouw situatie het handigst is.

[ Voor 15% gewijzigd door Verwijderd op 19-03-2009 21:14 ]

Pagina: 1