[OO-design] één entity, meerdere 'types'

Pagina: 1
Acties:

  • dingstje
  • Registratie: Augustus 2002
  • Laatst online: 02-01-2024
In mijn applicatie heb ik users. Elke user kan een of meerdere 'userclasses' hebben (vb. Producer, Assembler). Nu is het zo dat bepaalde userclasses extra gegevens vereisen (zo moet een Producer bijvoorbeeld een veld hebben om wat hij producet automatisch door te sturen naar een Assembler). Ik dacht om dit te gaan maken als volgt:

- User class
- Producer class die inherit van User, met het extra veld erin
- CountryManager class die inherit van User met een extra veld in

Nu is het probleem dat een user zowel CountryManager als Producer kan zijn (of een andere combinatie van classes). Tot op heden is het niet mogelijk voor een variable om twee types tegelijk te zijn, dus daar loop ik tegen een probleem aan.

Een mogelijke oplossing die ik bedacht is om gewoon één User class te maken met alle fields, en de fields die niet van toepassing zijn gewoon null te laten (staat nu ook zo in de database overigens). Maar gevoelsmatig lijkt mij dat niet zo'n mooie oplossing.

Is mijn gevoel verkeerd en is dat wel een mooie oplossing of heb ik het bij het rechte eind en kunnen jullie een betere oplossing aandragen? Alvast bedankt _/-\o_

N.B.: ik programmeer in PHP, maar dit zou niet mogen uitmaken vermoed ik

If you can't beat them, try harder


  • CodeCaster
  • Registratie: Juni 2003
  • Niet online

CodeCaster

Can I get uhm...

Ik zal wel verkeerd denken, maar is het juist niet beter als je hetgene wat een producer produceert op te slaan ín de producer-class, en niet in de user-class?

Anders moet je voor ieder nieuw type user je user-class uitbreiden...

Sowieso zie ik niet wat er niet kan kloppen aan $user1->assembler->assemble($user2->producer->getProduction())'

https://oneerlijkewoz.nl
Op papier is hij aan het tekenen, maar in de praktijk...


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 20-11 11:59

NMe

Quia Ego Sic Dico.

dingstje schreef op dinsdag 24 april 2007 @ 10:45:
N.B.: ik programmeer in PHP, maar dit zou niet mogen uitmaken vermoed ik
offtopic:
Jawel, dat maakt wel uit. ;) Sommige talen ondersteunen namelijk multiple inheritance, wat hier een uitkomst zou kunnen zijn. Al denk ik dat je in de meeste gevallen je ontwerp wel zo moet kunnen indelen dat je het nooit nodig zal hebben. :)

'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.


  • mulder
  • Registratie: Augustus 2001
  • Laatst online: 21:34

mulder

ik spuug op het trottoir

Niet echt een pattern kenner, maar is het Decorator pattern misschien iets?

oogjes open, snaveltjes dicht


  • dingstje
  • Registratie: Augustus 2002
  • Laatst online: 02-01-2024
Don Facundo schreef op dinsdag 24 april 2007 @ 11:19:
Niet echt een pattern kenner, maar is het Decorator pattern misschien iets?
Ziet er op het eerste zicht interessant uit, maar het probleem is dat ik die fields moet kunnen accessen. Dat is hier niet mogelijk omdat je één 'base-interface' moet hebben. Het volgende zou dus moeten kunnen:
PHP:
1
2
$user->getProducerSpecificField(); 
$user->getCountryManagerSpecificField();

Ik zie niet hoe dat mogelijk is met het decorator pattern, of mis ik iets?
-NMe- schreef op dinsdag 24 april 2007 @ 10:52:
[...]

offtopic:
Jawel, dat maakt wel uit. ;) Sommige talen ondersteunen namelijk multiple inheritance, wat hier een uitkomst zou kunnen zijn. Al denk ik dat je in de meeste gevallen je ontwerp wel zo moet kunnen indelen dat je het nooit nodig zal hebben. :)
Dan moet ik nog altijd voor elke mogelijke combinatie een nieuwe class gaan maken die inherit van de verschillende klassen. Lijkt me ook niet echt een nette oplossing...

If you can't beat them, try harder


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 07:54

Janoz

Moderator Devschuur®

!litemod

Multiple inheritance lijkt me hier niet echt een oplossing, maar ik ben sowieso neit zo'n voorstander van multiple inheritance. Er zitten nogal wat haken en ogen aan.

Bij het lezen van het probleem was het eerste wat mij te binnenschoot het splitsen van de personen en de taken. Een Producer is niet een Producer, maar een Person met een Producer Task. Zodra je dit verschil maakt inherit Producer niet van Person, maar van Task. Een person heeft vervolgens een set taken.

Toen ik vervolgens verder in het topic keek bleek dit inderdaad wel overeen te komen met het decorater pattern.

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


  • dingstje
  • Registratie: Augustus 2002
  • Laatst online: 02-01-2024
Kun je daar iets dieper op in gaan Janoz? Waar zet je dan de assembler naar wie zijn geproduceerde items by default naartoe moeten? Iets als $user->getTask('produce')->getDefaultAssembler() o.i.d.? En hoe regel je dat dan met CountryManager, van wie het specifieke gegeven de set countries waarvoor hij verantwoordelijk (en dus die hij kan managen) is.

If you can't beat them, try harder


  • mulder
  • Registratie: Augustus 2001
  • Laatst online: 21:34

mulder

ik spuug op het trottoir

dingstje schreef op dinsdag 24 april 2007 @ 11:31:
[...]

Ziet er op het eerste zicht interessant uit, maar het probleem is dat ik die fields moet kunnen accessen. Dat is hier niet mogelijk omdat je één 'base-interface' moet hebben. Het volgende zou dus moeten kunnen:
PHP:
1
2
$user->getProducerSpecificField(); 
$user->getCountryManagerSpecificField();

Ik zie niet hoe dat mogelijk is met het decorator pattern, of mis ik iets?
[...]
Dit moet uberhaupt niet mogelijk zijn. Bad design imho, een user is geen producer en een user is geen countrymanager.

oogjes open, snaveltjes dicht


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 07:54

Janoz

Moderator Devschuur®

!litemod

@dingstje: Ja, op die manier. Er is gewoon een CountryManager task die de set met countries heeft. Eerste ingeving voor die dingen is task, maar je zou het ook een rol kunnen noemen. Maar in principe is het inderdaad gewoon het decorator patern. Je kunt keurig in de link van Don Facundo lezen hoe dat in elkaar steekt.

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


  • ATS
  • Registratie: September 2001
  • Laatst online: 28-11 20:56

ATS

Ik denk niet dat je benadering met rollen hetzelfde is als het decoratorpattern eigenlijk. Het probleem met dit pattern is, zoals dingstje al opmerkte, dat je het gedrag van een klasse wel kan aanpassen, maar niet de interface. Dat is een serieuze beperking. Natuurlijk kan je daar wel weer een mouw aanpassen via een vorm van introspectie die je zou kunnen toevoegen, maar dan moet je alsnog gaan casten ofzo. Niet enorm elegant.
Het voorbeeld dat ik meer dan eens heb gezien is een window dat een scrollbar en een border moet gaan krijgen, in elke combinatie. Leuk en aardig om dat op te lossen met decorators, maar in een standaard, simpele versie van het pattern heb je na het aanmaken van je object geen toegang meer tot de verschillende objecten waaruit je gedecoreerde object bestaat. Hoe wil je op dat moment het bereik van die scrollbar aanpassen? Of hoe ga je de breedte of de kleur van je border aanpassen? Om hiervoor toegang te krijgen heb je toch een wat complexere oplossing nodig. Je hebt iets van een functie nodig die door de hierachie loopt en je, aan de hand van de naam van de decorator, dat betreffende object in de hierarchie geeft zodat je dat object kan casten van de basisklasse naar de specifieke decorator klasse en dan toegang kan krijgen tot een uitgebreidere interface. Zoiets dus:

code:
1
2
3
4
5
6
7
8
WindowBase decorator=0;
ScrollabbleWindowDecorator scrollDecorator=0;

decorator = decoratedWindow->getDecorator("scrollableWindow");
if (decorator) {
    scrollDecorator=cast<ScrollableWindowDecorator>(decorator);
    scrollDecorator->setScrollRange(0,400);
}


Uiteraard kan je ook nog dingen maken als:
bool isDecoratedBy(type)
list<type> listDecorators()

Dit zorgt voor nog wat meer introspectie, maar het blijft natuurlijk lastig.

Voor het toevoegen van een setje velden en eventueel wat daar bij horende functies die verder de functies van het basisobject niet veranderen is het een wat overdreven methode. Ik zou hier gewoon een map (in php een array met namen denk ik) maken met daarin je rol-specifieke dingen.

My opinions may have changed, but not the fact that I am right. -- Ashleigh Brilliant

Pagina: 1