[PHP/OOP] Object ontwerp bij collections/lists van objecten

Pagina: 1
Acties:

Onderwerpen


  • twiekert
  • Registratie: Februari 2001
  • Laatst online: 30-08 11:55
Sinds ik wat meer met OOP in PHP bezig ben loop ik nog wat tegen problemen aan met het bijhouden van lijsten van objecten in een ander object.

Praktisch voorbeeldje:
We hebben een invoice die 1 of meerdere invoicelines heeft.

verkorte invoiceline class
PHP:
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
class invoiceline {
  private $invoiceline_id,
      $invoice_id,
          $description,
      $saleprice,
      $amount;

  public function stapel getters&setters voor properties

  public function __construct() {
   //initialize alle vars op default waarden
 }

 public function select_invoiceline($p_id) {
   //query database voor invoiceline met p_id als PK 
   //en vul properties met database gegevens
 }

 public function update_db() {
  //deze functie checkt aan de hand van properties wat er moet gebeuren:
  // insert, update of delete en roept de betreffende methode aan
 }

 public functions insert_invoiceline, update_invoiceline, delete_invoiceline

 public function get_total_saleprice() {
   return $this->get_saleprice() * $this->get_amount(); 
 }
}



invoice class
PHP:
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
class invoice {
  private $invoice_id,
          $invoicelines, //array of invoicelines
          $invoicedate;


  public function __construct() {
   //initialize alle vars op default waarden
 }

 public function select_invoice($p_id) {
   //query database voor invoice data
   // en vul properties met DB gegevens
 }

 
 public function update_db() {
  //deze functie checkt aan de hand van properties wat er moet gebeuren:
  //insert, update of delete en roept de betreffende methode aan
  //deze methoden updaten ook de invoicelines
 }

 public functions insert_invoice, update_invoice, delete_invoicee


 public function get_total_saleprice() {
   $total_saleprice = 0;
   foreach ($this->invoicelines as $invoiceline) {
    $total_saleprice += $invoiceline->get_total_saleprice();
   }

   return $total_saleprice;
 }


OP het moment dat je een instantie van de invoice class aanmaakt en een invoice selecteerd, moeten de bijbehorende invoicelines uiteraard ook geselecteerd worden. Het is nogal nutteloos om overbodige queries uit voeren dus ipv van dat ik de invoiceline->select_invoiceline method aanroep vul ik het invoiceline object 'handmatig' met de set methods.

invoice select method:
code:
1
2
3
4
1. vul de properties van de invoice met DB waarden
2. While (er nog invoicelines zijn) 
      2.1 Maak een nieuwe invoiceline instantie
      2.2 vul deze met de set_*() methoden


Dit gaat allemaal goed maar het wordt natuurlijk echt spannend als je een invoicelist class wilt maken die een collectie van invoices heeft en die weer een collectie van invoicelines.

de invoicelist class maakt op deze manier de invoices aan:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public function select_invoices() {

  //query uitvoeren
  //een select van alle invoices met een join op de invoicelines tabel


  while (er nog records zijn) {
   
   if (er een nieuwe invoice is) {
     //maak nieuw invoice object
     //vul properties met DB gegevens via set_* methods
   }

   //maak nieuw invoiceline object in huidig invoice object
   //vul properties met DB gegevens via set_* methods
   
 }
}



Nou werkt dit wel, maar het is nogal _ZWAAR_ als je 35 invoices met in totaal 1000 invoicelines inlaadt. Dat zijn dus 35 + 1000 + 1 instances voor een lijstje met invoices. de tijd om al deze objecten aan te maken is +- 0.7 seconden wat ik nogal lang vindt (op een P3-500, 512MB).
Nu zijn de echte classes nogal volgepropt met functionaliteit, de invoice class is +- 650 regels en de invoiceline class +- 450. Om een 1 enkele invoice compleet weer te geven is dat ook nodig maar voor een lijst met invoices niet.

Een invoicelijst hoeft alleen maar te weten:

- de invoice gegevens
- het totaal aantal invoice regels
- het totaalbedrag


Het totaal aantal invoicelines en het totaalbedrag zijn in dit object model alleen te achterhalen als alle objecten (invoice en invoicelines) aangemaakt worden (via de get_total_saleprice methods).


Wat zou ik in dit geval moeten doen?

- Functionaliteit verdelen in meerdere classes? (starten meet een readonly class en uitbreiden met database functies?)

- Bereken functies zoals totaal bedrag voor een invoice niet uitrekenen maar gewoon berekenen in een query en opslaan als property. Daardoor hoeven de invoicelines niet ingeladen te worden maar alleen de invoice zelf + totaalprijs en totaal aantal invoicelines.
Dit geeft natuurlijk problemen als je een invoice wijzigt, het totaalbedrag moet dan opnieuw uitgerekend worden. Daarnaast ziet het er vies uit om dit soort gegevens die je moet berekenen los op te slaan. en je hebt ook nog eens incomplete invoice objecten die geen invoicelines aangemaakt hebben maar ze staan wel in de database.

- De invoicelist class helemaal loskoppelen van de invoice en invoiceline classes en apart gegevens bijhouden in een array ipv een invoice object te instantieeren? Ook niet handig want nu moet je op 2 plaatsen bijhouden uit welke gegevens een invoice bestaat ipv op 1 plek: de invoice class;


Ik kom er niet echt uit en ik heb het idee dat ik gewoon wat fundamenteels fout doe bij het object ontwerp :)
Iemand ideeen om dit het beste aan te pakken ?