La vera domanda è: perché avere un repository separato per i commenti? Un repository fa da intermediario tra la business logic e un qualche tipo di storage o origine dati. Ma questo repository di commenti si trova tra un altro repository e l'archiviazione. Il modo in cui vengono memorizzati i commenti è solo un dettaglio di implementazione del repository Posta?
È possibile che la risposta sia no e che sia necessario un repository di commenti separato. Ciò indica che parti della logica aziendale trattano i commenti indipendentemente dal loro post principale e che la tua entità post non dovrebbe contenere un elenco di commenti. Invece, i commenti potevano conoscere direttamente i loro post padre. Per esempio. questo design ti consente di aggiornare Post senza dover salvare nuovamente tutti i commenti esistenti su quel Post.
Se si dispone di un repository di commenti separato e il repository di posta deve utilizzarlo, questa dovrebbe essere una dipendenza esplicita. Cioè la chiamata di new CommentRepository()
è abbastanza dubbia. Nella maggior parte dei casi il repository sarà definito come un'interfaccia e non dovresti creare un'istanza diretta di una classe di implementazione.
Se manterremo il tuo design originale dei Post, prenderei in considerazione la possibilità di scrivere il repository in questo modo:
interface CommentRepository {
void save(Comment comment);
...
}
interface PostRepository {
void save(Post post);
}
class PostRepositoryForDatabase implements PostRepository {
private CommentRepository commentRepo;
public PostRepositoryForDatabase(CommentRepository commentRepo) {
this.commentRepo = commentRepo;
}
@Override
public void save(Post post) {
... // save post body & metadata
for (Comment c : post.getComments()) {
commentRepo.save(c);
saveMapping(post, c);
}
}
private void saveMapping(Post post, Comment comment) { ... }
}
L'utilizzo di un repository separato come questo è per lo più soddisfacente, poiché tale dipendenza è ora esplicita. Questo non è ancora ottimo (perché il design Post / Comment nel tuo modello di dominio e nel tuo database è un po 'insolito), ma questi aspetti sono molto più difficili da risolvere.
Se si tratta di un campo verde, un tipico progetto di post / commento con repository potrebbe essere simile a:
class Post { ... }
class Comment { Post post; ... }
interface PostRepository {
void save(Post post);
void saveComment(Comment comment);
...
}
class PostRepositoryForDatabase implements PostRepository {
@Override
public void save(Post post) {
...
}
@Override
public void saveComment(Comment comment) {
...
}
}
Con uno schema del database
posts(id, ...)
comments(id, post_id → posts(id), ...)
vale a dire. la tabella di mappatura non è necessaria a meno che la relazione Messaggi ai commenti non sia molti a molti. Per questa relazione da uno a molti, la chiave esterna post_id
può far parte della tabella comments
.
Non è strettamente necessario disporre di repository separati per post e commenti poiché ritengo che il repository sia un'astrazione sulla stessa origine dati. Spesso vengono visualizzate classi separate in C # (che ereditano da un'interfaccia generica Repository<T>
) ma questa è una comodità specifica della lingua correlata a funzioni come reflection, LINQ e metodi di estensione.
Nel mio design alternativo, in che modo la logica di business aggiunge un commento a un post? Basta creare un commento per quel post e salvarlo:
Comment c = new Comment(post, user, body);
repo.saveComment(c);
Se abbiamo bisogno di un elenco di tutti i commenti su un post, il repository dovrebbe fornire un metodo appropriato:
interface PostRepository {
...
List<Comment> getCommentsForPost(Post p);
}
vale a dire. l'entità Post
non esporrà un metodo come getComments()
.