Implementazione del modello di repository che non conosce nulla sulla tabella del database e sui nomi delle colonne

5

Ho visto in giro per Internet e Github, implementazioni per il Repository di pattern di progettazione che conosce i nomi delle tabelle e delle colonne del database. Pensavo, se volevo lavorare con il database come plugin, che potevo scollegare e collegare un altro rispettando Open / Closed per il resto del mio codice, il mio repository non dovrebbe conoscere i nomi delle colonne del database che sto usando . Quindi, come implementare questo modello in modo che possa trasformare il risultato dal database in un'Entità del mio dominio, senza conoscere i nomi delle tabelle e delle colonne del database?

Poiché la mia lingua principale è PHP, ho visto che in Doctrine \ ORM puoi facilmente passare diversi file di configurazione yamls o xmls, mappando i nomi delle colonne ai nomi delle proprietà sull'entità, ma ... Non posso essere ostaggio di un implementazione della libreria, se voglio implementare raw PDO, o qualsiasi altra libreria per i miei repository che non rende questa idratazione immediata, la mia implementazione dovrebbe fare, quindi come?

Aggiornamento

Aggiornamento2
Perfavore,daiun'occhiataa: link

    
posta Leo Cavalcante 08.07.2014 - 17:28
fonte

2 risposte

3

Quello di cui stai parlando è inversione di dipendenza e incapsulamento. Il codice che si consuma vuole mantenere una dipendenza su alcuni mezzi per ottenere le entità di dominio, senza bisogno di sapere come ciò accada. Vuole un insieme di metodi su una scatola nera, che si aspetta di dare alcuni input e ottenere alcuni output: un'interfaccia.

Invece di fare in modo che il tuo codice dipenda da una concreta implementazione dell'accesso ai dati, fai affidamento su un'astrazione: l'interfaccia. Fintanto che il tuo codice chiamante conosce solo l'astrazione, non importa in che modo realizzi tale interfaccia, a patto che lo faccia correttamente.

Prendendo gli esempi Doctrine e PDO raw dalla tua domanda, potresti definire un'interfaccia come:

interface FooRepositoryInterface {
    public function getAFoo($id);
}

Con l'interfaccia in atto, puoi implementarla in qualsiasi modo tu ritenga opportuno:

public class DoctrineFoo implements FooRepositoryInterface {
    public function __construct(EntityManager $em){ ... }
    public function getAFoo($id){ 
        return $this->em->find("\Entity\Foo", $id);
    }
}

public class PDOFoo implements FooRepositoryInterface {
    public function __construct(PDO $pdo){ ... }
    public function getAFoo($id){ 
        $pdo->prepare("sql ...");
        $row = $pdo->fetchOne();
        return $this->makeFooFromRow($row);
    }     
}

Ciò consente agli altri moduli di dipendere felicemente dall'accesso ai dati in termini di interfaccia:

class FooBazer {
    public function doBaz(FooRepositoryInterface $repository, $id) {
        $foo = $repository->getAFoo($id);
        $foo->baz();
    }
}
    
risposta data 08.07.2014 - 17:45
fonte
3

Lo scopo del repository è di fornire un adattatore attorno al database. "Conosce il database", quindi il resto del codice non deve.

Quindi sembra abbastanza ragionevole per me che se si modifica lo schema del database, sarà necessario modificare (o sostituire del tutto) i repository. Il punto è che solo devono sostituire i repository, perché l'implementazione è nascosta dall'applicazione dall'interfaccia.

Se hai molti aggregati e un repository per ognuno di essi, quindi sostituirli all'ingrosso è difficile, potresti essere in grado di ottenere aiuto da un ORM, a seconda delle tecnologie che stai utilizzando. Ad esempio, un generico Repository<T> sembra essere piuttosto comune in C #.

Naturalmente, anche se stai usando un ORM, ci deve essere ancora del codice, da qualche parte, che conosce lo schema del database. In questo modo di solito è nascosto in un file di mappatura XML (che ovviamente ha i suoi vantaggi e svantaggi).

Modifica in risposta ai tuoi commenti:

Non vedo davvero quello che stai cercando di ottenere. Nel tuo progetto, sembra che gli oggetti "Idrazione" assumano la responsabilità di comunicare con il database e restituire un oggetto dominio. Quindi, se si modifica lo schema del database, è comunque necessario modificare tutti gli oggetti Hydration. La tua proposta non risolve il tuo problema percepito: deve esserci un codice da qualche parte che conosca lo schema del database.

Ma il tuo design è molto più complicato: c'è un ulteriore livello (il Repository stesso) che sostanzialmente non fa nulla.

public class FooRepository
{
    private IFooHydration _fooHydration;

    public FooRepository(IFooHydration fooHydration)
    {
        _fooHydration = fooHydration;
    }

    public Foo Get(int id)
    {
        return _fooHydration.Get(id);
    }

    public void Save(Foo entity)
    {
        _fooHydration.Save(entity);
    }
}

È molto più semplice usare un IRepository e scrivere diverse implementazioni di questo per i diversi metodi di persistenza. In breve, il repository è quello che si plug-in quando si cambia database.

    
risposta data 11.07.2014 - 00:21
fonte