[JAVA/Design] Kan niet tot een goed design komen *

Pagina: 1
Acties:

  • Banaan
  • Registratie: Maart 2000
  • Laatst online: 21-08 13:12
Ik heb momenteel wat problemen om tot een goed design van mijn applicatie te komen. Het gaat om het volgende: De applicatie moet prijzen berekenen voor producten, zodate er een offerte uitgebracht kan worden. Op dit moment (maar die zou in de toekomst kunnen veranderen) zijn de producten op te delen in twee groepen, productGroepA en productGroepB. Iedere productgroep heeft een n-aantal producten onder zich. De twee productgroepen hebben twee dingen in common (ben nederlandse term ff kwijt :) )
1. Ze moeten beiden een prijs gaan berekenen
2. Ze hebben een class (params met hun getters en setters) waarin alle input en output parameters staan (input zijn ongeveer 10 parameters, output ongeveer 30, vandaar de aparte class)

De daadwerkelijke berekening van de prijzen is per groep totaal verschillend. Om het nog lastiger te maken, is op dit moment nog niet bekend hoe de berekening van productGroepB er uit gaat zien.

De berekening voor productGroepA bestaat uit een 7-tal subberekening, die voor alle producten in die groep hetzelfde zijn, op 1 na. Deze laatste berekening is ook weer verschillend per type layout van de offerte.

Nu ben ik zelf tot het volgende design gekomen, maar ik weet gewoon dat het niet klopt.. er zit o.a. nog veel te veel dubbele code in. Zal na de code een alternatief wat ik bedacht had bespreken, maar ook dat is een fout design volgens mij.

Abstract class for ieder product (geen interface vanwege de factory method)

- Messenger is een interface voor de classes die alle input/output parameters in zich hebben.
- De factory method geeft de Messenger door aan de constructor van de producten, dat klopt volgens mij ook niet.. hoe kan ik daar beter mee om gaan?

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
public abstract class Product {

  protected Logger log = null;

  public abstract void calculate(Messenger messenger) 
      throws QEException;

  public abstract String getName();

  public abstract Messenger getParameters();

  public static Product getInstance(int productID, Messenger params) 
      throws QEException {
    switch (productID) {
      case PRODUCT1:
        return new Product1(params);
      case PRODUCT2:
        return new Product2(params);
      case PRODUCT3:
        return new Product3(params);
      (etc. etc. )
      default:
        throw new QEException("QE9999", "Invalid productID");
    }
  }
}


Abstract class voor ieder product van productGroepA:
(ProductGroepAMessenger is dus een type Messenger)
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public abstract class ProductGroepA extends Product {

  protected ProductGroepAMessenger productGroepAMessenger = null;

  protected abstract void calculate1() throws QEException;

  protected abstract void calculate2() throws QEException;

  protected abstract void calculate3() throws QEException;

  protected abstract void calculate4() throws QEException;

  protected abstract void calculate5() throws QEException;

  protected abstract void calculate6() throws QEException;

  protected abstract void calculate7() throws QEException;

  public Messenger getParameters() {
     return productGroepAMessenger;
  }
}


Een product uit productGroepA:

- Hoewel bij elke calculate method hetzelfde staat, is dit in werkelijkheid verschillend voor iedere method.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
public class Product1 extends ProductGroepA {

  private static final String PRODUCTNAME = "Product1";

  public Product1 (Messenger params) {
    super(params);

    log = Logger.getLogger(Product1.class.getName());
  }
  
  public void calculate() throws QEException {
    log.info("Calculating 1");
    calculate1();

    log.info("Calculating 21");
    calculate2();

    log.info("Calculating 3");
    calculate3();

    log.info("Calculating 4");
    calculate4();

    log.info("Calculating 5");
    calculate5();

    log.info("Calculating 6");
    calculate6();

    log.info("Calculating 7");
    calculate7();
  }

  protected void calculate1() throws QEException {
    // prepare for calculation
    // calculate -> gebeurt in een andere class
    // process results
  }

  protected void calculate2() throws QEException {
    // prepare for calculation
    // calculate -> gebeurt in een andere class
    // process results
  }

  protected void calculate3() throws QEException {
    // prepare for calculation
    // calculate -> gebeurt in een andere class
    // process results
  }

  protected void calculate4() throws QEException {
    // prepare for calculation
    // calculate -> gebeurt in een andere class
    // process results
  }

  protected void calculate5() throws QEException {
    // prepare for calculation
    // calculate -> gebeurt in een andere class
    // process results
  }

  protected void calculate6() throws QEException {
    // prepare for calculation
    // calculate -> gebeurt in een andere class
    // process results
  }

  protected void calculate7() throws QEException {
    switch (layoutID) {
      case LAYOUT1:
        // do stuff
      case LAYOUT2:
        // do stuff
      (etc. etc.)
    }
  }

  public String getName() {
    return PRODUCTNAME;
  }
}


Als alternatief had ik overwogen om de code die voor elk product van productGroepA hetzelfde is (calculate1 t/m 6) in de abstract class ProductGroepA te plaatsen, maar ook dat is een slecht design.

Beide oplossingen gaan echter in tegen het idee van "favor composition over inherentance" en "prefer interfaces to abstract classes".. hoe kan ik mijn design aanpassen om het wel goed (of in ieder geval beter) te maken?

Voor de duidelijkheid: Ik heb de code aangepast om tot een simpele en duidelijke benaming te komen. Mochten er toch onduidelijkheden zijn, schroom niet te vragen!

Sorry voor deze lap tekst, maar hoop dat jullie mij hier wat mee kunnen helpen!

  • mafti
  • Registratie: Januari 2003
  • Laatst online: 11-11-2022

mafti

Kopyright Liberation Front

Erm,

het is praktischer om een uml-diagram te tonen. is wat overzichtelijker.

maar maak van je calculates ook gewoon aparte statische classes en roep
ze aan binnen je product-calculate.

voorts zijn je produktgroepen als class niet interessant want ze voegen niks toe aan je model. het is simpelweg een groepId in je produkt-class.

basically heb je dus je produkt-classen die allemaal overerven van Produkt.
en je calculate-classjes die weer overerven van een algemene calculate.

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 21-08 18:33
Wat je wilt is eenzelfde operatie ( het berekenen van de prijs van een product ) op verschillende manieren implementeren ( De prijs van pruduct A wordt op een andere manier berekend dan de prijs van product B )

Dit ruik naar een Strategy design pattern.

Je maakt bijvoorbeeld een PriceCalculation interface die een Product als parameter heeft ( of de losse info die nodig is om de prijs te berekenen als dat er niet al te veel zijn ).

Je kunt dan bijvoorbeeld een factory gebruiken om voor de verschillende producten te bepalen welke strategy nodig is.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • hobbit_be
  • Registratie: November 2002
  • Laatst online: 04-07-2025
Hmm 1 vraagje: zo'n calculate - wat wordt daar gedaan - hij blijkt niets terug te geven dus wat doet ie. Als je iets heel flexibels willen hebben en vooral iets dat niet vast hangt kun je misschien beter met een rule systeem gaan.

stel: ProductA heeft 10 berekeningen - elk van die berekening is IMHO een classe. Ie iets dat met data werkt.

zo zou je dus een 'Calculate Interface' kunnen maken en dan per product in het begin van je programma (en zelfs in realtime) de rules (calculates kunnen aanpakken).

eg: (vast nodig)

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class AddTax implements Calculation
{
     public calculate(Calculation aCalc)
     {
           aCalc.setTotal(aCalc.getTotal()*0.33);
     }
}

Product extends CalculationsImpl.
{
    ArrayList tCalcs = [new AddInterest(), new AddProfitMargin(), new AddTax()]; 
    
    for-each (....)
}


natuurlijk gaat die alleen als je calculate een soort communality heeft wat mij wel leek te zijn.

Overgines interface vs abstract. Idd interfaces zijn mooier maar je kan dan ook normaal zetten:

Abstract implements (part of) Interface en dan voor je classe

class Doh extends Abstract - (zodoende ineens een interface).

code met veel Case gevallen vind ik persoonlijk niet mooi en erg unflexible - verander ik steeds in een HashMap + Factory model. (ie geen new Product1,2,3) gewoon:

HashMap t = [("Product1", new Product1.getFactory()), new .... ];

zodoende blijft heel je engine erg simpel en kun je met een beetje reflectie met xml of zo de hashmap aanmaken. De overhead is meestal miniem en bij vele products is het gewoon sneller dan een case/...

Ook log4j is cool maar kan als je oppast veel speed penalty geven maak steeds gebruik van een paar eigen settings:

if (debuglevel.info) log.info(.....);

(veel belangrijker voor log.debug natuurlijk).

  • Banaan
  • Registratie: Maart 2000
  • Laatst online: 21-08 13:12
hobbit_be schreef op 07 August 2003 @ 14:09:
Hmm 1 vraagje: zo'n calculate - wat wordt daar gedaan - hij blijkt niets terug te geven dus wat doet ie.
De resultaten van die berekening worden opgeslagen in een Messenger (standaard bean met getters en setters), vandaar dat ie niks terug geeft..
Als je iets heel flexibels willen hebben en vooral iets dat niet vast hangt kun je misschien beter met een rule systeem gaan.
Wat jij hier een rule systeem noemt, is feitelijk het Strategy Designpattern toch?
<< java code >>
Ja en hier raak je me toch enigszins kwijt, en dan vooral op regel 9. Waarom extend Product (dan zal wel Product1 moeten zijn? Product lijkt me meer een naam voor een interface) de abstract class CalculationsImpl? Kan je me dat uitleggen? Oftewel wat doet die CalculationsImpl?

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 21-08 18:33
Banaan schreef op 07 August 2003 @ 16:05:
[...]

Wat jij hier een rule systeem noemt, is feitelijk het Strategy Designpattern toch?

[...]
Zoals ik hierboven al uitlegde, is een strategy niet dat rulesysteem. Het kan zijn dat de strategy die wordt gekozen ( de implementatie van de prijsberekening ) via een soort rulesysteem wordt bepaald.

Dit is echter zozeer niet onderdeel van de strategy, meer van een factory achtig iets.

Met deze regel:
Java:
1
Product extends CalculationsImpl


Wil de schrijver ( volgens mij ) zeggen dat produkt een 'prijsberekingsinterface' implementeert.
Zelf zou ik die interface niet door het product laten implementeren maar door een apart object die kiest voor de juiste berekening afhankelijk van het produkt.
De totalen zou ik dan door een 'Order' object laten bepalen, die bijhoudt welke produkten er in een order zitten.

just my 2 euro-cts

[ Voor 37% gewijzigd door farlane op 07-08-2003 19:22 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 07:56

alienfruit

the alien you never expected

je zou het toch ook dynamische kunnen maken dus dat de rekenregels dmv. van scripting worden berekend en/of uit een configuratie bestand wordt geschreven ipv. dat je het oplost in je functioneel ontwerp.

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 21-08 18:33
alienfruit schreef op 07 August 2003 @ 19:23:
je zou het toch ook dynamische kunnen maken dus dat de rekenregels dmv. van scripting worden berekend en/of uit een configuratie bestand wordt geschreven ipv. dat je het oplost in je functioneel ontwerp.
Naar mijn idee moet je het dan nog in je ontwerp oplossen, ook al doe je het met scripting oid.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 07:56

alienfruit

the alien you never expected

Ja. Maar dan hoef je iig niet je code en alles opnieuw te compileren als de formule wijzigd. Naja, rekenregels is iig een full proofed idee heeft voor me vader altijd perfect gewerkt :X

[ Voor 35% gewijzigd door alienfruit op 07-08-2003 20:21 ]


  • Banaan
  • Registratie: Maart 2000
  • Laatst online: 21-08 13:12
alienfruit schreef op 07 August 2003 @ 19:23:
je zou het toch ook dynamische kunnen maken dus dat de rekenregels dmv. van scripting worden berekend en/of uit een configuratie bestand wordt geschreven ipv. dat je het oplost in je functioneel ontwerp.
Nee dat is niet mogelijk in dit geval. Mijn uitleg was een ietwat versimpelde beschrijving van de werkelijke situatie. De meeste van de berekeningen bestaan uit meer dan 2 A4'tjes met specs.. niet iets wat je dus even in een config bestandje kan plaatsen :)
farlane schreef op 07 August 2003 @ 19:13:
[...]

Zoals ik hierboven al uitlegde, is een strategy niet dat rulesysteem. Het kan zijn dat de strategy die wordt gekozen ( de implementatie van de prijsberekening ) via een soort rulesysteem wordt bepaald.

Dit is echter zozeer niet onderdeel van de strategy, meer van een factory achtig iets.
OK, nu heb ik even wat info gezocht over het strategy pattern, maar ik heb ergens het idee dat het niet helemaal toepasbaar is voor mijn situatie. Een typisch voorbeeld (ik kom het iig meerdere keren tegen) is dit:

Java:
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
31
32
33
34
35
public interface InterfaceAlgorithm {     
    public void executeAlgorithm(); 
}//End of Interface

public class Algorithm1 implements InterfaceAlgorithm {
    public void executeAlgorithm() {
        prt();
    }

    public void prt() {
        System.out.println(" Class is Algorithm1.");
    }
}//End of Class 

public class Algorithm2 implements InterfaceAlgorithm {
    public void executeAlgorithm() {
         prt();
    }

    public void prt() {
         System.out.println(" Class is Algorithm2.");
    }
}//End of Class

public class Context  {
    public Context(InterfaceAlgorithm algo) {
         _algo = algo;
    }

    public void contextInterface() {
         _algo.executeAlgorithm();
    }

    private InterfaceAlgorithm _algo; 
} //End of Class 

Wat men hier Context noemt, zou in mijn geval een product zijn (zo niet, dan is onderstaand verhaal ook niet meer kloppend). Ik kan echter niet een algoritme meegeven aan de constructor van een product, omdat een product gebruik maakt van meerdere (7) algoritmes.

Ik denk dus dat ik een deel hiervan wel kan gebruiken, namelijk een algoritme interface, met allemaal algoritmes die dit implementeren, en dat in combinatie met zoiets wat hobbit_be voorstelde, namelijk per product:

Java:
1
2
3
4
5
6
public class Product1 implements Product. 
{ 
    ArrayList tCalcs = [new Calculation2, new Calculation5(), new Calculation7()];  
     
    for-each (....) 
}

Lijkt dat logisch?

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 21-08 18:33
Het is een mogelijkheid om je produkt de interface te laten implementeren, maar ...

[selfquote]
Zelf zou ik die interface niet door het product laten implementeren maar door een apart object die kiest voor de juiste berekening afhankelijk van het produkt.
[/selfquote]
Ik kan echter niet een algoritme meegeven aan de constructor van een product, omdat een product gebruik maakt van meerdere (7) algoritmes.
Meerder algoritmes bij elkaar is 1 groot algoritme (object ) dat op een speciale manier wordt 'geconstruct' ( Weet ff niet hoe ik het in fatsoenlijk Engels en/of Nederlands moet verwoorden :) )

Een factory is een object die andere objecten construct. :)

[ Voor 35% gewijzigd door farlane op 08-08-2003 12:01 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • Banaan
  • Registratie: Maart 2000
  • Laatst online: 21-08 13:12
OK, theoretisch snap ik wat je bedoelt, maar mijn probleem is dat ik niet weet hoe ik dat in de praktijk moet toepassen. Kan je hier een klein voorbeeld van geven, of me in ieder geval wat termen geven waarmee ik kan gaan zoeken?

  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 07:56

alienfruit

the alien you never expected

Ja. Misschien in configuratiebestand niet maar als je scripttaaltje hebt die acties kan uitvoeren. Bijv. een casuskaart selecteren, bepaalde waardes van velden opvragen en er vervolgens berekeningen op uitvoeren als datum controles, optellen etc. :)

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 21-08 18:33
Banaan schreef op 08 August 2003 @ 12:08:
[...]

OK, theoretisch snap ik wat je bedoelt, maar mijn probleem is dat ik niet weet hoe ik dat in de praktijk moet toepassen. Kan je hier een klein voorbeeld van geven, of me in ieder geval wat termen geven waarmee ik kan gaan zoeken?
Stel je hebt een object Order waarin al de produkten die besteld zijn zijn opgeslagen. ( Per groep of per produkt, afhankelijk wat handiger is voor jouw. )

Dit Order object vraagt aan de CalulationFactory welk CalculationObject hij moet gebruiken om de prijs te berekenen.
Dit CalculationObject is dus de strategy.

De factory heeft om dat te bepalen informatie nodig over de produkten, afzonderlijk of per groep of whatever, afhankelijk wat je requirements zijn ( Die A4'tjes van je :) )
( Je kunt het hele Order object meegeven aan de factory, zodat die alle informatie van de order kan gebruiken om vast te stellen welke CalculationObject hij moet teruggeven. )

Vervolgens vraagt het Order object aan het pas verkregen CalculationObject om de prijs te berekenen van de order.
Dit calulationobject kan objecten bevatten die de algoritmes voorstellen.
( Je kunt het hele Order object meegeven aan het CalculationObject, of enkel de afzonderlijke produkten, wat jij wil )

Op die manier zorg je ervoor dat alle variatie over de verschillende berekenmethoden in het calculationobject zitten, terwijl het maken en bewaren en kiezen van die berekenmethoden in de factory zitten.

Krijg je nu nieuwe rekenmethoden erbij, maak je een nieuw CalculationObject en pas je de factory aan zodat hij dit nieuwe object kiest als het nodig is.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • Banaan
  • Registratie: Maart 2000
  • Laatst online: 21-08 13:12
Volgens mij heb je nu een extra laag complexiteit toegevoegd, die niet in mijn systeem zit, namelijk die Order. Er zal altijd (uhm nouwja, er staat in ieder geval helemaal niks op de planning om dat te veranderen) maar 1 product tegelijk besteld worden, nooit meerdere.
=> Interessante vraag trouwens: Ik kan me wel voorstellen dat ze ooit (over meer dan een jaar) combinatie aanbiedingen willen gaan doen, dus dan heb je feitelijk wel een order met meerdere producten. Moet je daar nu al rekening mee gaan houden in je design als dat een nu onnodige complexiteit toevoegd?

Maar om even door te gaan op jouw voorbeeld: Als ik het goed begrijp bepaalt de samenstelling van de order welk CalculationsObject je terug krijgt? Dat impliceert dus dat voor iedere combinatie van producten, je een apart CalculationsObject hebt. Dat gaat dan toch op een gegeven moment enorm uit de klauwen lopen?

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Banaan schreef op 08 augustus 2003 @ 15:15:
[...]

Volgens mij heb je nu een extra laag complexiteit toegevoegd, die niet in mijn systeem zit, namelijk die Order. Er zal altijd (uhm nouwja, er staat in ieder geval helemaal niks op de planning om dat te veranderen) maar 1 product tegelijk besteld worden, nooit meerdere.
=> Interessante vraag trouwens: Ik kan me wel voorstellen dat ze ooit (over meer dan een jaar) combinatie aanbiedingen willen gaan doen, dus dan heb je feitelijk wel een order met meerdere producten. Moet je daar nu al rekening mee gaan houden in je design als dat een nu onnodige complexiteit toevoegd?

Maar om even door te gaan op jouw voorbeeld: Als ik het goed begrijp bepaalt de samenstelling van de order welk CalculationsObject je terug krijgt? Dat impliceert dus dat voor iedere combinatie van producten, je een apart CalculationsObject hebt. Dat gaat dan toch op een gegeven moment enorm uit de klauwen lopen?
De factory bepaalt inderdaad aan de hand van de Order welke CalculationsObject je terug krijgt.

Dit betekend echter niet meteen dat je voor alle combinaties een apart CalculationsObject krijgt. Het is namelijk aan de Factory om te bepalen welk object terug wordt gegeven. Je mag zelf bepalen hoe de Factory dat beslist.

Je zou bijvoorbeeld aan de hand van het aantal producten kunnen beslissen. Stel je hebt 2 CalculationsObjecten. Eentje voor alle orders met minder dan 5 producten en de ander voor alles met 5 of meer producten. Het ligt er maar net aan wat je selectiecriteria zijn. Op dezelfde manier kan je dit ook toepassen als het maar over 1 product gaat. door het product mee te geven aan de factory kan de factory bijvoorbeeld naar het gewicht van het product kijken om te bepalen welke CalculationsObject je terug krijgt.

“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.”


  • Banaan
  • Registratie: Maart 2000
  • Laatst online: 21-08 13:12
rwb schreef op 08 August 2003 @ 16:15:
[...]

De factory bepaalt inderdaad aan de hand van de Order welke CalculationsObject je terug krijgt.

Dit betekend echter niet meteen dat je voor alle combinaties een apart CalculationsObject krijgt. Het is namelijk aan de Factory om te bepalen welk object terug wordt gegeven. Je mag zelf bepalen hoe de Factory dat beslist.

Je zou bijvoorbeeld aan de hand van het aantal producten kunnen beslissen. Stel je hebt 2 CalculationsObjecten. Eentje voor alle orders met minder dan 5 producten en de ander voor alles met 5 of meer producten. Het ligt er maar net aan wat je selectiecriteria zijn. Op dezelfde manier kan je dit ook toepassen als het maar over 1 product gaat. door het product mee te geven aan de factory kan de factory bijvoorbeeld naar het gewicht van het product kijken om te bepalen welke CalculationsObject je terug krijgt.
Toch denk ik dat dit te complex is voor mijn situatie. Zoals ik al zei bestaat ieder product uit een x aantal berekeningen. Ik zou dus in mijn geval het product aan de factory geven, en deze retourneert dan een CalculationsObject. Vanwege het feit dat per product het aantal berekeningen kan verschillen, en ook de berekening zelf kan verschillen, zal ieder product dus een eigen CalculationsObject gaan krijgen. (En hier maak ik vast een denkfout, zie alleen niet welke).
Waarom zou ik dan niet meteen de functionaliteit van CalculationsObject in mn product stoppen op de manier zoals al eerder vermeldt. Oftewel wat is de toegevoegde waarde van CalculationsObject bij mij?

Even klein voorbeeld:
- Messenger heeft alle input en outputparameters
- Niet relevante code is weggelaten

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public interface InterfaceCalculation {
    public void executeCalculation(Messenger messenger) ;
} // End interface

public class Calculation1 implements InterfaceCalculation {
    public void executeCalculation(Messenger messenger) {
        // do stuff
    }
} // End class

public class Product1 {
    public void calculate(Messenger messenger) {
        ArrayList calculations = new ArrayList();
        calculations.add(new Calculation1());
        calculations.add(new Calculation2());
        // etc

        ....

        while (calculationsIterator.hasNext()) {
            calc.executeCalculation(messenger);
        }
} // End class

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 21-08 18:33
Banaan schreef op 08 augustus 2003 @ 15:15:
Er zal altijd (uhm nouwja, er staat in ieder geval helemaal niks op de planning om dat te veranderen) maar 1 product tegelijk besteld worden, nooit meerdere.
=> Interessante vraag trouwens: Ik kan me wel voorstellen dat ze ooit (over meer dan een jaar) combinatie aanbiedingen willen gaan doen, dus dan heb je feitelijk wel een order met meerdere producten. Moet je daar nu al rekening mee gaan houden in je design als dat een nu onnodige complexiteit toevoegd?
Uit een boek dat ik recentelijk hab aangeschaft ( met dank aan Alarmnummer :) ) :
A note about customers

...
They often use the term 'always' when they mean 'usually'
They often use the term 'never' when they mean 'seldom'
...
:)
Maar die keus is natuurlijk geheel aan jou om te maken.
Maar om even door te gaan op jouw voorbeeld: Als ik het goed begrijp bepaalt de samenstelling van de order welk CalculationsObject je terug krijgt? Dat impliceert dus dat voor iedere combinatie van producten, je een apart CalculationsObject hebt.
Kijk, het ligt helemaal aan de specs die je gekregen hebt of dit zo is, dat kan ik niet bekijken. Voor hetzelfde geld hebben ze alle behalve 1 hetzelfde CalculationsObject.
Waarom zou ik dan niet meteen de functionaliteit van CalculationsObject in mn product stoppen op de manier zoals al eerder vermeldt. Oftewel wat is de toegevoegde waarde van CalculationsObject bij mij?
Je hebt op die manier de 'variabele' gedeelten van de 'constante delen' gescheiden. Bovendien, als je twee produkten hebt die dezelfde berekeningen gebruiken heb je in jouw ontwerp een minder optimale situatie, je moet hetzelfde calulationsobject ( in je code CalculationX ) meerdere keren instantieren.

Nogmaals, het is een oplossing wat ik aandroeg, niet _de_ oplossing. :)

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Je kan je CalculationsObject natuurlijk ook een soort Container van Calculation Objecten maken. Zo kan je voor alle aparte berekeningen die je hebt een aparte class maken. De factory bepaaltd dan aan de hand van een database of config filede goede Calculation objecten en die stop hij in een Container ( CalculationsObject ). Deze container heeft dan een method calculate. Deze combineert dan alle berekeningen in de goede volgorde. Zo hoef je dus niet voor elk product een verschillend Calculation object te maken. Als de berekeningen echter per Product zo specefiek zijn dat er echt niks van te hergebruiken is in andere producten dan kan je het natuurlijk gewoon in product stoppen. Maar ik denk dat er toch wel een aantal berekeningen meer als 1 keer voor zullen komen. Op deze manier is het ook makkelijker om later nog eens extra producten toe te voegen met een combinatie van de berekeningen van de andere producten.

ff een voorbeeldje van wat ik bedoel

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface ICalculation
{
    void Calculate( Product product );
}
public class CombinedCalculation : ICalculation
{
    ArrayList list = new ArrayList();
    
    public void Calculate( Product product )
    {
          foreach( Calculation calculation in list )
               calculation.Calculate( product );
    }

    public void AddCalculation( Calculation calculation )
    {
          list.add( calculation );
    }
}


En dan maak je bijvoorbeeld een TaxCalculation en een RebateCalculation en die kan je dan in je CombinedCalculation stoppen en in je Factory terug geven

[ Voor 27% gewijzigd door Woy op 08-08-2003 19:20 ]

“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.”


  • hobbit_be
  • Registratie: November 2002
  • Laatst online: 04-07-2025
sorry voor no reply - was in sixflags vandaag ;)

je bent erzelf zowat achter waar ik op doelde. Het doel van die calculations is het reusable van hun en ook volgorde swapping, run time loading etc. Hetzelfde heb ik gedaan voor een type-cast in Java. zo kan ik bijvoorbeeld: ooData.convert(someVar, Integer.class); door een algorithme kan ik een reeks van rules aflopen (die in runtime worden toegevoegd) om ervoor te zorgen dat de conversie altijd lukt. ZO heb ik bijvoorbeeld 1maal een Integer 2 Date convertor en ook een Date 2 String convertor. Deze twee rules zijn afzonderlijk maar door de enfine kan ik ook perfect Int 2 String (en vice versa) doen.

In jouw geval zou ik dit gebruiken om je 'product' groups gewoon voor te stellen als een reeks van zaken die je kan doen. Zo zijn ze zeer extensible, flexible en meeste code is dan mooi hidden.

De factories (static methods ;) zijn dan een gemakkelijke manier om ze creeren. (en dus ook voor runtime (xml-based) loading. ). Natuurlijk geld hier wel dat die calculations ook echt iets fundamenteels hetzelde doen. In dit geval lijkt me dat wel zo. Je kan ook nadenken over dat elke 'rule' (calculation) eigen parameters kent die je dan ook kunt inladen.

sommige delen van onze code zien er zo uit

code:
1
2
3
4
5
<datatype type="email">
    <extends type="string" / >
    <add-rule class="requiredRule" />
    <add-rule class="emailValidator" />
</>


jouw zou kunnen zijn:

code:
1
2
3
4
5
6
7
8
<productgroup type="a">
   <add-calculation type="tax">
        <rate>12%</rate>
   </>
   <add-calculation type="rebate">
        <rate>100</rate>
   </>
</>


dit is allemaal heel erug leuk (en bij ons zit er dan nog wat <if> <case> <else> enzo bij ;) maar kan ook overkillzijn voor jouw app. Hoewel een interface met:

Calc1, Calc2, Calc3, .... voor mij niet door de beugel kan :) (dan nog liever 1 method met duidelijke comments). Als de calculations niet worden herbruikt heb je hier ook 0 boodschap aan - daarvoor te weinig info.

Door jouw PG (productgroup) een interface te geven van 'Calculateable' kun je aan een PG verscheidene Calculation (interface) hangen...
Pagina: 1