[OO Alg] Klasse met dynamische attributen?

Pagina: 1
Acties:

  • JaymzHetfield
  • Registratie: Februari 2001
  • Laatst online: 18-07 21:06
Ik ben een beetje in UML aan het ontwerpen en liep tegen de volgende kwestie aan. Ik heb het idee dat hier wel een design pattern o.i.d. voor bestaat en heb daar ook naar gezocht maar niks gevonden.

DE SITUATIE (fictief)
In het systeem worden verschillende soorten klanten bijgehouden, elke klant heeft een aantal gegevens als naam, adres etc. Maar de overige eigenschappen van een klant zijn afhankelijk van het soort klant dat het is.
Bijvoorbeeld: Van een zwembadklant wordt naast naam en adres ook de zwemdiploma bijgehouden. En van een schoenwinkelklant wordt naast naam en adres ook de schoenmaat bijgehouden.
Het leuke is dat de soorten klanten niet vast staan, in het systeem kan een nieuwe klantsoort worden ingevoerd waarvoor bijvoorbeeld naast de naam en adres ook de muziekale voorkeur wordt bijgehouden. Als er vervolgens een nieuwe klant in het systeem ingevoerd wordt, dan moeten naam en adres sowieso ingevoerd worden en afhankelijk van het soort klant nog een aantal andere eigenschappen.

IMPLEMENTATIE
Stel ik heb een klasse Klant. Klant heeft een aantal methodes die er niet toe doen en een aantal attributen als naam adres woonplaats die ELKE klant heeft. Hoe kan je dan het best bovenstaande situatie implementeren? Ik zat te denken aan een associatie van de klasse Klant naar de klasse KlantType. En dan zou je bijvoorbeeld in KlantType kunnen bijhouden welke klanteigenschappen er bij dat klanttype horen (zoals schoenmaat, oogkleur, leeftijd, whatever). Die eigenschappen moet je dan bij Klant zien te krijgen om de eigenschappen daar een waarde te geven o.i.d. (schoenmaat=43).

VRAGEN:
1. Hoe zou je dit het beste kunnen aanpakken?
2. Bestaat er een design pattern die dit probleem omschrijft?

PS Als iemand een duidelijkere topictitel weet...

Metal up your ass


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:02
Een abstracte class Klant maken die een attribuut naam en adres heeft en een aantal virtuele functies.
Dan ga je specifieke klanten gaan inheriten van die abstracte class en de virtuele functies gaan overriden.

Dmv polymorphisme wordt de juiste functie dan uitgevoerd.

Bv:

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
class Klant
{
  private string   naam;
  private string   adres;
  public virtual void Ingeven()
  {
        Console.WriteLine("naam:");
        Console.ReadString(naam);
        Console.WriteLine ("adres:");
        Console.ReadString(adres);
   }
};

class ZwemKlant :  Klant
{
   private string diploma;

    public override void Ingeven()
    {
         base.Ingeven();
         Console.WriteLine ("diploma:");
         Console.ReadString (diploma);
    }
};

[ Voor 58% gewijzigd door whoami op 01-04-2003 13:10 ]

https://fgheysels.github.io/


  • GarBaGe
  • Registratie: December 1999
  • Laatst online: 15:48
Gewoon een attribuut maken met de naam: XML-config en eentje met XML-data.
Dan kan je in XML al je dynamische datatypes bij ;)

Ryzen9 5900X; 16GB DDR4-3200 ; RTX-4080S ; 7TB SSD


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
Je bent niet 100% duidelijk. Moeten er klanttypes dynamisch worden toegevoegd, zonder dat daar een programma wijziging voor nodig is?
Zo ja, dan werkt whoami's oplossing niet: De subtypes zijn statisch vastgelegd, en een extra subtype toevoegen@runtime werkt niet. Sowieso is dat model onvolledig; wat als een zwembadkant opeens ook in de schoenwinkel koopt.

Een makkelijkere oplossing is mogelijkerwijs een "Generiek attribuut" class, waarvan "zwembad" en "schoenwinkel" concrete instances zijn. Een enkele klant heeft dan 1 of meer van deze generieke attributen ( Geen 0; dan was het geen klant ). Een functie die op schoenwinkel klanten werkt vraagt dan om het attribuut 'schoenwinkel' van die klant.

Als de subtypes dynamisch zijn, dan zijn de concrete instances "zwembad" e.d. objecten van het type "Generiek attribuut", en dan zijn de mogelijke waarden daarvan beperkt tot een enkel type(bv string). Zijn de subtypes statisch, dan zijn het derived types van "Generiek attribuut", en dan zijn er geen beperking aan de waardes. Je kunt dus kiezen wat er flexibel is, maar dat betekent dat je moet kiezen wat er vastligt.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • JaymzHetfield
  • Registratie: Februari 2001
  • Laatst online: 18-07 21:06
MSalters schreef op 01 April 2003 @ 13:20:
Je bent niet 100% duidelijk. Moeten er klanttypes dynamisch worden toegevoegd, zonder dat daar een programma wijziging voor nodig is?
Ja.
Zo ja, dan werkt whoami's oplossing niet: De subtypes zijn statisch vastgelegd, en een extra subtype toevoegen@runtime werkt niet.
Inderdaad, misschien dat ik daar niet duidelijk genoeg in was.
Een makkelijkere oplossing is mogelijkerwijs een "Generiek attribuut" class, waarvan "zwembad" en "schoenwinkel" concrete instances zijn. Een enkele klant heeft dan 1 of meer van deze generieke attributen
Dat lijkt me wel een idee. Ik ga even nadenken of dat nog beperkingen oplevert.
( Geen 0; dan was het geen klant ). Een functie die op schoenwinkel klanten werkt vraagt dan om het attribuut 'schoenwinkel' van die klant.
0 kan volgens mij ook, want sommige winkels hebben genoeg aan de standaardeigenschappen van Klant en hoeven geen schoenmaat of andere eigenschappen te weten.
Als de subtypes dynamisch zijn, dan zijn de concrete instances "zwembad" e.d. objecten van het type "Generiek attribuut", en dan zijn de mogelijke waarden daarvan beperkt tot een enkel type(bv string).
Subtypes zoals je ze noemt, zijn inderdaad dynamisch. Het probleem is dan een beetje dat enkele type. Je noemde al het enkele type (bv string), natuurlijk kan je wel als string "43" opgeven, maar dan zou iemand er ook "groot" van kunnen maken en dat wil je niet. Ik vraag me dus af of je ook @runtime een klanteigenschap schoenmaat erbij kan verzinnen en dat je opgeeft dat schoenmaat van het type int is.

Metal up your ass


Verwijderd

lekker simpel houden

class Klant
-----------------------
- Properties properties
- String type
-----------------------

Uiteraard de nodige getters en setters en vergelijkings methodes. Ook makkelijk als je ze weg moet schrijven naar een db

  • JaymzHetfield
  • Registratie: Februari 2001
  • Laatst online: 18-07 21:06
Ik ben er even mee verder gegaan en kwam eigenlijk op de oplossing van Markvleth uit.

Het volgende had ik bedacht
3 classes: Klant, KlantType en Property.

Class Property = string propertyNaam en string propertyValue en wat methods

Class Klant = naam, adres e.d., een referentie naar een ProductType en een verzameling Property objecten (in een Vector of wat dan ook).

Class KlantType = typenaam + een verzameling Property objecten.
Deze properties bevatten de eigenschappen die over een klant van dat type moeten worden bijgehouden en de defaultwaardes, dus bijvoorbeeld:
naam="schoenmaat" waarde="58"
naam="onbetrouwbaar" waarde="nee"

Dat zou dan als volgt moeten werken:
Aan een bepaald KlantType object wordt gevraagd creeerNewKlant(), deze returnt een Klant object. Dit nieuwe Klant object bevat allemaal default waardes voor naam e.d. en de verzameling properties van het Klant object is een kopie van de verzameling properties van het KlantType. Het nieuwe Klant object zou in het voorbeeld dus 2 properties hebben:
naam="schoenmaat" waarde="58"
naam="onbetrouwbaar" waarde="nee"
Alle eigenschappen van het nieuwe Klant object worden vervolgens op het scherm getoond, de waardes kunnen aangepast worden door de gebruiker (naam="pietje", schoenmaat="41" etc.). Als de gebruiker de waardes heeft ingevoerd klikt ie op save o.i.d. en het nieuwe Klant object wordt in de DB geinsert.

PROBLEMEN
Best aardig, maar er zijn nu 2 problemen:

1: Er wordt besloten dat er over klanten ook een haarkleur wordt bijgehouden, het Klanttype krijgt er een property bij met naam="haarkleur" en waarde="onbekend". Het probleem is dat nieuw aangemaakte klanten wel een property haarkleur krijgen, maar de oude klanten geen property haarkleur hebben. Je zou dan alle klanten langs moeten lopen en bij elke klant de nieuwe property moeten toevoegen... aardig intensief.

2: De property-naam is een string, dat is ok. Maar de waarde is ook een string, dat is niet ok. Eigenlijk zou je verschillende type waardes voor een property moeten kunnen bijhouden.

Iemand suggesties voor deze problemen?

Metal up your ass


  • Orphix
  • Registratie: Februari 2000
  • Niet online
Ik zou voor elke primitieve een aparte class maken die allemaal afgeleiden zijn van een (abstracte) klasse Property.

Ik heb dit onlangs ook toegepast voor een programma. Een voordeel was dat ik een virtual method in Property had: getInputControl(). Dit gaf een control terug die de desbetreffende property kon bewerken. In het geval van een string was dit gewoon een textbox, in het geval van een numerieke property was dit een spinbox (of hoe dat ook alweer heet). Ik kan hier later types (subclasses) aan kunnen toevoegen en dan werkt het direct.

Iets anders, wat is het verschil tussen NAW gegevens en andere properties? Is het niet makkelijker om gewoon alles als properties te beschouwen, dus ook naam en adres?

Je eerste probleem is denk ik onontkombaar. De intensiviteit zal wel meevallen, het is niet iets wat dagelijks gebeurt. Je komt er denk ik niet onder uit om zulke acties expliciet te gaan programmeren.

Verwijderd

Op zich zou het mooiste zijn als je een hoofdklasse hebt (Klant) en daar alle andere klasses van erft.
Maar dat is waarschijnlijk niet 'dynamisch' genoeg.

Daarnaast voor je probleem:
Waarom neem je niet gewoon een array op, met een methode die hier op lijkt:
Java:
1
2
3
public void addProperty( String aName, int aValue ) {
  this.theProperties[ aName ] = aValue;
}

[ Voor 4% gewijzigd door Verwijderd op 03-04-2003 13:20 ]


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op 03 April 2003 @ 13:19:
Daarnaast voor je probleem:
Waarom neem je niet gewoon een array op, met een methode die hier op lijkt:
Java:
1
2
3
public void addProperty( String aName, int aValue ) {
  this.theProperties[ aName ] = aValue;
}
Ik wist niet dat dit in java kon ;) Het lijkt me handiger om een map te gebruiken waar je iets in kan plaatsen:

code:
1
2
3
public void addProperty(String key, Object value){
    map.put(key,value);
}

Verwijderd

Alarmnummer schreef op 03 April 2003 @ 13:28:
Ik wist niet dat dit in java kon ;)
Het was ook maar een gokje :P.
Het lijkt me handiger om een map te gebruiken waar je iets in kan plaatsen:
Is inderdaad wat slimmer, zit je tenminste niet vast aan die vaste grootte.

  • Reptile209
  • Registratie: Juni 2001
  • Laatst online: 00:04

Reptile209

- gers -

JaymzHetfield schreef op 03 April 2003 @ 12:12:
1: Er wordt besloten dat er over klanten ook een haarkleur wordt bijgehouden, het Klanttype krijgt er een property bij met naam="haarkleur" en waarde="onbekend". Het probleem is dat nieuw aangemaakte klanten wel een property haarkleur krijgen, maar de oude klanten geen property haarkleur hebben. Je zou dan alle klanten langs moeten lopen en bij elke klant de nieuwe property moeten toevoegen... aardig intensief.
Dan zou je een standaard-interface kunnen ontwerpen voor het aanmaken van een nieuwe property. Die interface moet dan ook vragen om een "default" voor klanten die hem (nog) niet hebben. Die default (bijv. naam="haarkleur" en waarde="een beetje bruin/grijs met blonde lok") kan dan worden toegevoegd aan alle klanten in je DB. En als je 'm toch leeg laat, zou de interface daar ook de master-default-waarde van "onbekend" aan kunnen toekennen.

Evt is dit nog uit te breiden met expressies voor de voorwaarde waaraan een klant moet voldoen voor een bepaalde standaardwaarde (bijv. haarkleur=blond als het een zwembadklant is [chloor :) ], zwart bij een schoendrager [schoenpoets] en bruin bij de rest).

[ Voor 4% gewijzigd door Reptile209 op 03-04-2003 22:06 ]

Zo scherp als een voetbal!


Verwijderd

Je kunt het ook nog op een iets andere manier aanpakken en dan zijn volgens mij alle problemen uit de weg. Schrijf een interface (abstracte klasse) Klant die er ongeveer zo uitziet:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface Klant {
  //uniek id voor klanttype
  public int getId();
  
  //naam voor het klanttype
  public String getName();

  //toevoegen van een waarde aan key alleen als de property al bestaat
  public boolean setProperty(String key, Object value );

  // fully qualified name van de class van dit object
  public String getPropertyType(String key);

  public Object getProperty(String key);
}


Een beschrijvendeiclass voor een klant
Java:
1
2
3
4
5
6
7
8
public class KlantSkeleton {
  //voeg een nieuw property toe en geef aan wat voor type het is (bv java.lang.String)
  public void addProperty(String key, String qName){}

  //levert de properties 
  public Properties getProperties(){}

}


En dan een klasse die een klant object maakt
Java:
1
2
3
4
5
6
public class KlantFactory{
  //maak een klant aan de hand van de skeleton, zorg dat een overeenkomstig
  // skeleton zorgt dat het id van een klant hetzelfde is. 
  // deze klasse heeft dus een inner class die de interface Klant implementeerd
  public Klant create(KlantSkeleton skeleton){}
}


Volgens mij is dit wel een degelijke oplossing

  • Mickman
  • Registratie: Juni 2001
  • Laatst online: 29-03 18:11
Hij heeft het over UML en jullie beginnen te smijten met programmeer code.

Volgens UML kan je dan een klasse Klant hebben met een specialisatie naar een soort klant met daarbij contraints of een klant meerdere specialisatie mag hebben.

Verwijderd

Ik zie nog geen implementatie hoor, dit is praktisch uml...

Verwijderd

Mickman schreef op 04 April 2003 @ 13:09:
Volgens UML kan je dan een klasse Klant hebben met een specialisatie naar een soort klant met daarbij contraints of een klant meerdere specialisatie mag hebben.
Volgens mij (en UML) kan je geen dynamische specialisaties (zoals je voorsteld) opnemen en dat zou wel een oplossing zijn.

Daarnaast denk ik dat de bovenstaande oplossingen voldoen.

Verwijderd

Kan je hiervoor niet het state-design pattern gebruiken?
Pagina: 1