Seguendo questa descrizione del modello di deposito, abbiamo tre principali preoccupazioni che richiedono le proprie classi:
- Il "Repository", che accetta e restituisce i modelli di dominio.
- Il "Gateway", che prende i dati dal modello di dominio e restituisce una sorta di dati generici
- Il "Fabbrica", che prende i dati "generici" dal Gateway e li associa al Modello di Dominio
Un repository ha bisogno di due oggetti per fare il suo lavoro:
- Un "gateway" per l'interazione con l'archiviazione persistente
- Una "fabbrica" per tradurre i dati dal gateway nel modello di dominio
Quando si ha a che fare con linguaggi strongmente tipizzati, ogni variabile ha bisogno di un "Tipo". Se si specifica tale tipo e lo si utilizza nel repository, lo si abbina al modello di dati sottostante del livello di persistenza e quindi lo si passa al factory, ma gli esempi che trovo mostrano il repository che tratta direttamente sia il gateway < em> e Factory.
Un esempio delle interfacce per un "Blog"
public interface IBlogGateway
{
// Returns generic data type so switching persistence
// does not require refactoring in the Repository
object Find(long id);
}
public interface IBlogFactory
{
// Accepts generic data type so switching persistence
// does not require refactoring in the Repository
Blog Make(object data);
}
public interface IBlogRepository
{
Blog Find(long id);
}
E l'implementazione delle interfacce:
public class SqlBlogGateway : IBlogGateway
{
public object Find(long id)
{
DataTable table = // Find from database
DataRow row = table.Rows.Count == 1
? table.Rows[0]
: null;
// Implicit cast from DataRow to object (this code smells)
return row;
}
}
public class SqlBlogFactory : IBlogFactory
{
public Blog Make(object data)
{
// Explicit cast from object to DataRow (this code smells)
DataRow row = (DataRow)data;
Blog blog = new Blog(long.Parse(row["ID"].ToString()))
{
Title = row.Field<string>("TITLE")
};
return blog;
}
}
public class BlogRepository : IBlogRepository
{
private IBlogFactory factory;
private IBlogGateway gateway;
public BlogRepository(IBlogFactory factory, IBlogGateway gateway)
{
this.factory = factory;
this.gateway = gateway;
}
public Blog Find(long id)
{
object data = gateway.Find(id);
if (data == null)
return null;
return factory.Make(data);
}
}
In particolare sto lavorando con C # in .NET, ma questo è applicabile a qualsiasi linguaggio orientato agli oggetti strongmente tipizzato. Quando persistiamo in un database, potremmo occuparci di DataSet
, DataTable
e DataRow
oggetti (o array
per PHP o HashTable
per Java). Quando arriva il momento di ridefinire il "Gateway" per persistere in un servizio Web, questi tipi non sono sufficienti, perché un servizio web non è probabile che utilizzi un DataTable
. Invece specificherà il proprio oggetto Data Transfer.
Potresti avere il Gateway che restituisce un tipo object
, e "Factory" prende un tipo object
e lo lancia sul tipo corretto, ma poi perdi tutti i vantaggi di un linguaggio strongmente tipizzato, come ad esempio compilare controllo del tempo e Intellisense / Completamento automatico in un IDE. Inoltre, se si esegue il cast di object
e si torna a un tipo specifico per il gateway, è possibile introdurre alcuni errori di runtime funky e difficili da debugare. Sembra che il repository abbia bisogno di un gateway e un gateway ha bisogno di una fabbrica, ma il repository non dovrebbe conoscere la fabbrica.
Per eliminare la necessità di refactoring del repository quando si modificano i meccanismi di persistenza, quale tipo di dati dovrebbe restituire il gateway?