In OOP, posso popolare (inizializzare) un oggetto usando l'iniezione del costruttore al momento della creazione dell'oggetto, o dell'iniezione setter, dopo il tempo di creazione.
Mi piace l'idea di popolare l'oggetto al momento della creazione tramite il costruttore, per i parametri dell'oggetto che sono essenziali per l'oggetto. E usa i metodi setter per cose che non sono essenziali o secondarie.
E tutto andava bene.
Fino a quando ho scoperto DataMapper
pattern. Nel modello I
- carica i dati dal database (attenzione ai dati)
- mappare le colonne dello schema ai parametri dell'oggetto (problemi di mappatura)
- crea / aggiorna / elimina / restituisce l'oggetto al suo chiamante (gestione della gestione degli oggetti)
Sono abbastanza contento che DataMapper sia essenzialmente il gestore per l'oggetto, creando quindi l'oggetto, caricando i dati e quindi popolando quell'oggetto. Se tutte e 3 le preoccupazioni precedenti condividono la stessa funzione, non vi è alcun problema in quanto sembrano integrarsi perfettamente insieme.
problema
Il problema sorge quando inizio a separare le preoccupazioni. Vale a dire, la preoccupazione di mappatura. La preoccupazione di mappatura dovrebbe riguardare solo se prendere i nomi delle colonne dello schema DB e copiare i dati dall'oggetto risorsa DB sulle variabili dei parametri del campo dati del nuovo oggetto. Per me si traduce in questo
- accetta un oggetto creato come parametro di input
- riempi l'oggetto dallo schema DB tramite il mapping (utilizzando setter per private vars o direttamente se vars sono pubblici)
- restituisce l'oggetto compilato al suo chiamante.
Penso che la preoccupazione per la mappatura non dovrebbe essere la creazione dell'oggetto. Ciò significa che la capacità di mappatura non può utilizzare l'inizializzazione del costruttore .
Domanda
Che cosa posso fare per utilizzare la preoccupazione di associazione separata e utilizzare ancora l'inizializzazione del costruttore?
Possibili soluzioni alternative
- Utilizza solo i metodi di inizializzazione setter [abbandona l'inizializzazione del costruttore anche quando lo desideri]
- racchiudono due diversi problemi di gestione dell'oggetto (ovvero la creazione [significa capacità di inizializzarlo tramite il costruttore]) e il mapping schema-oggetto all'interno della stessa classe. [abbandona SRP]
Esempio di codice
Per chiarezza - vedi commenti
class ProductDataMapper
{
public function dataConcern($id)
{
$sql = "SELECT model as name FROM product where id = {$id}";
$result = db_query($sql);
$data = db_fetch_array($result);
return $data;
}
public function mappingConcern($data)
{
//schema to property mapping (to separate concerns)
$parameters = array();
$parameters['name'] = $data['schema_column_name_in_db'];
//In order to use constructor initialization, mapping concern
//has to be the place to *create* the product (using new)
//my question deals with separating 'object creation' from 'object mapping'
//init via constructor - this is the *undesirable* concern for a mapper
$product = new Product($parameters);
//init via setters
foreach ($data as $key => $value) {
$setter = 'set' . ucfirst($key);
$product->$setter($value);
}
return $product;
}
public function getProduct($productId)
{
$data = $this->dataConcern($productId);
$product = $this->mappingConcern($data);
return $product;
}
}
Aggiorna
Sto pensando di poter separare la creazione dell'oggetto con la mappatura in una preoccupazione separata.
Questa preoccupazione sarà Object-Creation-and-Schema-Mapping-To-Object-via-Constructor
.
Vale a dire, ancora non perfetto, perché ci saranno due problemi di mapper
- mapper che crea e inizializza l'oggetto tramite il costruttore
- mapper che utilizza i setter per popolare l'oggetto