Ho un problema del mondo reale che proverò ad astrarre in un esempio illustrativo.
Quindi immagina di avere oggetti dati in un albero, in cui gli oggetti genitore possono accedere ai bambini e i bambini possono accedere ai genitori:
// Interfaces
interface IParent<TChild> { List<TChild> Children; }
interface IChild<TParent> { TParent Parent; }
// Classes
class Top : IParent<Middle> {}
class Middle : IParent<Bottom>, IChild<Top> {}
class Bottom : IChild<Middle> {}
// Usage
var top = new Top();
var middles = top.Children; // List<Middle>
foreach (var middle in middles) {
var bottoms = middle.Children; // List<Bottom>
foreach (var bottom in bottoms) {
var middle = bottom.Parent; // Access the parent
var top = middle.Parent; // Access the grandparent
}
}
Tutti e tre gli oggetti dati hanno proprietà che sono conservate in due archivi di dati (ad esempio un database e un servizio Web) e devono riflettere e sincronizzarsi con i negozi. Alcuni oggetti richiedono solo dal servizio web, alcuni solo scrivono su di esso.
Data Mapper
Il mio pattern preferito per l'accesso ai dati è Data Mapper , perché separa completamente il gli oggetti dati stessi dalla comunicazione con l'archivio dati:
class TopMapper {
public Top FetchById(int id) {
var top = new Top(DataStore.TopDataById(id));
top.Children = MiddleMapper.FetchForTop(Top);
return Top;
}
}
class MiddleMapper {
public Middle FetchById(int id) {
var middle = new Middle(DataStore.MiddleDataById(id));
middle.Parent = TopMapper.FetchForMiddle(middle);
middle.Children = BottomMapper.FetchForMiddle(bottom);
return middle;
}
}
In questo modo posso avere un mapper per archivio dati, e costruire l'oggetto dal mapper che voglio, e quindi salvarlo usando il mapper che voglio.
C'è un riferimento circolare qui, ma immagino che non sia un problema perché la maggior parte delle lingue può semplicemente memorizzare i riferimenti di memoria agli oggetti, quindi non ci saranno in realtà dati infiniti.
Il problema con questo è che ogni volta che voglio costruire un nuovo Top
, Middle
o Bottom
, ha bisogno di costruire l'intero albero degli oggetti all'interno della proprietà Parent
o Children
, con tutte le richieste dell'archivio dati e l'utilizzo della memoria che ciò comporta. E nella vita reale il mio albero è molto più grande di quello qui rappresentato, quindi questo è un problema.
Richieste nell'oggetto
In questo gli oggetti richiedono il loro Parent
se Children
se stessi:
class Middle {
private List<Bottom> _children = null; // cache
public List<Bottom> Children {
get {
_children = _children ?? BottomMapper.FetchForMiddle(this);
return _children;
}
set {
BottomMapper.UpdateForMiddle(this, value);
_children = value;
}
}
}
Penso che questo sia un esempio del schema del repository . È corretto?
Questa soluzione sembra accurata: i dati vengono richiesti dall'archivio dati solo quando ne hai bisogno, e successivamente vengono archiviati nell'oggetto se desideri richiederlo nuovamente, evitando un'ulteriore richiesta.
Tuttavia, ho due diverse origini dati. C'è un database, ma c'è anche un servizio web, e devo essere in grado di creare un oggetto dal servizio web e salvarlo sul database e poi richiederlo di nuovo dal database e aggiornare il servizio web.
Questo mi rende anche un po 'a disagio perché gli oggetti dati stessi non ignorano più l'origine dei dati. Abbiamo introdotto una nuova dipendenza, per non parlare di una dipendenza circolare, rendendo più difficile il test. E gli oggetti ora mascherano la loro comunicazione con il database.
Altre soluzioni
Ci sono altre soluzioni che potrebbero occuparsi del problema dei negozi multipli ma significa anche che non ho bisogno di creare / richiedere tutti i dati ogni volta?