Oggetti OOP, oggetti nidificati e DAO

4

Ecco qualcosa che continuo a cercare di capire quale sia la soluzione migliore. Ho avuto questo problema mentre lavoravo con PHP e Java, quindi è una comprensione fondamentale del problema OOP. Gli esempi sono in PHP.

Diciamo che ho alcuni oggetti qui. Song, Artist, ArtistProfile, User.

Quindi in alcuni casi voglio che ArtistProfile e una serie di oggetti User (subscribers) chiamino l'Artista (ad esempio la pagina del profilo dell'artista), in altri casi voglio solo le informazioni sull'Artista, come quando si visualizza una pagina del canzone.

Dovrei nidificare un oggetto come parte di un altro o dovrei creare oggetti più specifici per usi diversi.

Opzione 1: nidificata

Class Song {
   private $songId;
   private $songName;
   private $year;
   private $Artist; //Artist object
}

Class Artist {
   private $artistId;
   private $name;
   private $age;
   private $subscriberArr; //Array of User objects which then have more nested objects such as a Role object, Profile object
   private $profile; //Profile object which could also have more nested objects
}

Class User {
   private $userId;
   private $name;
   private $age;
   private $role; //Role object
   private $profile; //UserProfile object
}

Opzione 2: crea più oggetti

Class Song {
   private $songId;
   private $songName;
   private $year;
   private $artistId;
}

Class Artist {
   private $artistId;
   private $age;
   private $name;
}

Class User {
   private $userId;
   private $name;
   private $age;
   private $roleId;
}

Class SongWithArtist {
   private $song; //Basic Song object
   private $artist; //Basic Artist object
}

Class ArtistWithProfile {
   private $artist; //Basic artist object
   private $profile; //Profile object
   private $subscriberArr; //UserDisplay object containing basic User object
}

 Class UserWithProfile {}

L'opzione 1 significa sprecare un sacco di tempo / risorse per raccogliere informazioni che potrebbero non essere necessarie per quella pagina ma più facili da gestire. L'opzione 2 è caotica e richiede di tenere traccia di quale oggetto è ciò che è più veloce e meno chiamate db. Qual'è l'opzione "corretta" e / o esiste una terza opzione corretta?

    
posta user103555 30.09.2013 - 02:14
fonte

2 risposte

3

Should I be nesting one object as part of another or should I be creating more specific objects for different usages.

  1. Segui prima i principi OO che significa "oggetti più specifici". In questo modo le tue classi potrebbero "allinearsi" con lo schema del tuo database o no, ma non lasciare che lo schema DB abbia una buona idea di progettazione OO.

  2. Principi di responsabilità singola ti aiuteranno a capire in che classi costruire. SRP significa, ad esempio, che Song è una canzone. Non è un artista, non è un elenco di abbonati, quindi non dovrebbe contenere materiale per artisti o iscritti. Solo brani.

  3. Quanto sopra significa che avrai molte piccole, cose completamente funzionali, - classi. Con "pienamente funzionale" intendo, se un Song è un name , date e id allora questo è ciò che è contenuto. periodo. Il fatto che un certo artista canta quella canzone non inerentemente, definisce fondamentalmente cos'è un Song . Questo significa che altre classi modellano relazioni come "il repertorio di brani di un artista" per esempio.

  4. Piccole classi funzionali portano a buoni DAO e flessibilità per l'interfaccia utente.

Option 1 means wasting a lot of time/resources grabbing information I may not need for that page but easier to manage. Option 2 is messy and requires keeping track of which object is what but faster and far less db calls

  1. Stai cadendo vittima di ottimizzazione prematura. Come fai a sapere in anticipo che l'opzione 2 avrà "meno chiamate DB?" Che cosa significa comunque?

  2. Questo è semplicemente il modo sbagliato di pensare alle tue classi / modelli di dominio. Questo è il motivo per cui si finisce per duplicare lo schema del DB:

.

Class SongWithArtist {
  private $song; //Basic Song object
  private $artist; //Basic Artist object
}

Quando ciò che dovresti avere è qualcosa che descrive il mondo reale:

Class ArtistPortfolio {
    private Artist $theArtist;
    private List<Song> $portfolio;  // list of songs (s)he sings 
}

Class ArtistSubscribers {
    private Artist $theArtist;
    private List<User> $subscribers;  // list of people who like this artist
}

// And it would probably make sense to combine the above 2 classes:

Class ArtistProfile {
    // an Artist object, not just an id. We're doing OBJECT oriented programming.
    private Artist $theArtist;

    private List<Song> $portfolio;  // list of Song objects 
    private List<User> $subscribers; // list of User objects
}

// and if you need a list of profiles...
Class ArtistProfiles {
    private List<ArtistProfile> $profiles; // a list of type ArtistProfile

    public ArtistProfile GetProfileByArtist (Artist thisArtist){}
    public ArtistProfile GetProfileByName (string name) {}
    public ArtistProfile GetProfileById (string id) {}
}

// I'd say a ArtistProfile could be part of an Artist..

Class Artist {
    private $id;
    private $name;
    private ArtistProfile $profile; // this is composition.
}


//In lieu of the above, an DAO oriented Artist composition ...
// Just go with the refactoring flow!
Class Profile {
    private $id;
    private $name;
    private $birthdate
}

 Class Repertoire {
    // a Profile object, not just an id. We're doing OBJECT oriented programming.
    private Profile $theArtist;

    private List<Song> $portfolio;  // list of Song objects 
    private List<User> $subscribers; // list of User objects
}

Class Artist {
    private Profile $me;
    private Repertoire $myStuff; 
}

Troppe chiamate DB!

NON. Puoi creare un'istanza di un oggetto Artist senza inserire $myStuff e, a turno, posticipare il popolamento degli elenchi $subscribers / portfolio finché non è necessario. Si chiama lazy loading.

    
risposta data 08.10.2013 - 01:28
fonte
1

Credo che ciò che si vuole fare durante la programmazione in generale sia evitare la duplicazione dei dati.

Quando si progetta un database relazionale, ci sono 4 tipi di relazioni:

  • one-to-one
  • uno-a-molti
  • many-to-one
  • molti-a-molti

Per una relazione molti-a-molti, hai una "tabella dei collegamenti" in un database in cui di solito i due ID dei due record sono collegati tra loro.

Oltre ai due ID record collegati, una tabella di link può avere qualsiasi altro dato associato tra le due tabelle del database con la tabella di collegamento many-to-many.

Ad esempio,

class DBRecord {
    private $recordID; // a BIGINT, auto-incrementing field, the primary key
}

class Product extends DBRecord {
    private $productID; // an ID that the user can set
    private $productName;
    private $suggestedRetail;
    ...
}

class Vendor extends DBRecord {
   private $vendorID; // an ID that the user can set
   private $vendorName;
   private $contactID;
   ...
}

class ProductVendors extends DBRecord {
   private $productRecordID; // this ID never changes
   private $vendorRecordID;  // this ID never changes
   private $wholesaleCost;   // the cost of a product can be different by vendor
}

In questo esempio, gli oggetti delle classi: Product, Vendor e ProductVenders sono molto simili ai record presenti nel database. Potresti leggere un'intera tabella di database in un array.

$products = readAll();
$vendors = readAll();
$productVendors = readAll();

A seconda della dimensione del set di dati nel numero di record, potresti non volerli leggere tutti nella RAM.

Quando hai troppi record per leggerli tutti nella RAM, puoi impostare le relazioni tra gli oggetti per rispecchiare le relazioni tra le tue tabelle di database nel tuo database relazionale:

// database code is encapsulated in this class
class DB {
   ...
}

// this class implements functionality common to all subclasses
abstract class DBTable {
   private $db;
   private $internalName; // the SQL name for this database table
   private $displayName;  // the name that the user sees for this db table
   public lookup($productID) {
       ...
   }
}

class Products extends DBTable {
   ...
}

class Vendors extends DBTable {
    ...
}

class ProductVendors extends DBTable {
   ...
}

È così che ho fatto relazioni molte-a-molti, e funziona anche per dataset di grandi dimensioni come forse con 100.000 record di prodotto.

  • Uno-a-molti e molti-a-uno sono solo il rovescio della medaglia

    class PurchaseOrderLineItem extends DBRecord {
    }
    
    class PurchaseOrder extends DBRecord {
        private $lineItems;
        public loadLineItems() {
           ...
        }
        public saveLineItems() {
           ...
        }
    }
    

Un elemento pubblicitario di un ordine di acquisto può essere presente solo in un documento di ordine di acquisto, ma un documento di ordine di acquisto può contenere molti elementi pubblicitari. Questo in genere non è un numero enorme di elementi pubblicitari, quindi li carico tutti nella RAM, in un array.

  • Relazioni one-to-one

    class Product extends DBRecord {
        private $itemRecordID;
        private $inventoryOnHand;
        ...
    }
    
    class InventoryCount extends DBRecord {
        private $itemRecordID;
        private $inventoryCounted;
    }
    

Questi due record sono una relazione uno-a-uno. Quando si conta tutto l'inventario in un negozio, per ogni prodotto è presente un solo conteggio e per ciascun conteggio esiste un solo prodotto.

Quindi, questi sono i quattro tipi di relazioni. Penso che la soluzione più generale sia il mirror del database relazionale, ma non lo faccio sempre, come nel caso degli ordini di acquisto che "contengono" i loro elementi pubblicitari.

Fai attenzione ai problemi con più utenti Il famoso problema degli aggiornamenti persi.

Non duplicare i dati Vedi "Forme normali".

Data di nascita del negozio - non età In genere è meglio non archiviare un'età, ma una data di nascita e avere una funzione di accesso chiamata "getAge ()" per calcolare e restituire un'età.

    
risposta data 30.09.2013 - 15:39
fonte

Leggi altre domande sui tag