J'ai un scénario commun pour lequel je cherche des conseils auprès de personnes plus expérimentées en matière de DDD et de modélisation de domaine en général.
Imaginons que je commence à construire un moteur de blog, et que la première exigence soit qu'après la publication d'un article, les utilisateurs puissent commencer à poster des commentaires sur celui-ci. Cela commence bien, et conduit à la conception suivante :
public class Article
{
public int Id { get; set; }
public void AddComment(Comment comment)
{
// Add Comment
}
}
Mon contrôleur MVC est conçu comme suit :
public class ArticleController
{
private readonly IRepository _repository;
public ArticleController(IRepository repository)
{
_repository = repository;
}
public void AddComment(int articleId, Comment comment)
{
var article = _repository.Get<Article>(articleId);
article.AddComment(comment);
_repository.Save(article);
return RedirectToAction("Index");
}
}
Maintenant tout fonctionne bien, et cela répond à l'exigence. Dans l'itération suivante, nous avons une exigence selon laquelle chaque fois qu'un commentaire est publié, l'auteur du blog doit recevoir un courriel l'en informant.
À ce stade, j'ai deux choix possibles. 1) Modifier l'article pour exiger un IEmailService (dans le ctor ?) ou obtenir un EmailService à partir d'une référence statique à mon conteneur DI
1a) Cela semble assez laid. Je crois que cela enfreint certaines règles du modèle de domaine dont mes entités connaissent les services ?
public class Article
{
private readonly IEmailService _emailService;
public Article(IEmailService emailService)
{
_emailService = emailService;
}
public void AddComment(Comment comment)
{
// Add Comment
// Email admin
_emailService.SendEmail(App.Config.AdminEmail, "New comment posted!");
}
}
1b) Cela semble aussi très laid, j'ai maintenant besoin d'un conteneur DI configuré auquel on accède de manière statique.
public class Article
{
public void AddComment(Comment comment)
{
// Add Comment
// Email admin
var emailService = App.DIContainer.Resolve<IEmailService>();
emailService.SendEmail(App.Config.AdminEmail, "New comment posted!");
}
}
2) Créez un IArticleService et déplacez la méthode AddComment() vers ce service plutôt que sur l'entité Article elle-même.
Cette solution est plus propre je crois, mais l'ajout d'un commentaire est maintenant moins découvrable et nécessite un ArticleService pour effectuer le travail. Il semble que l'ajout d'un commentaire devrait appartenir à la classe Article elle-même.
public class ArticleService
{
private readonly IEmailService _emailService;
public ArticleService(IEmailService emailService)
{
_emailService = emailService;
}
public void AddComment(Article article, Comment comment)
{
// Add comment
// Email admin
_emailService.SendEmail(App.Config.AdminEmail, "New comment posted!");
}
}
public class ArticleController
{
private readonly IRepository _repository;
private readonly IArticleService _articleService;
public ArticleController(IRepository repository, IArticleService articleService)
{
_repository = repository;
_articleService = articleService;
}
public void AddComment(int articleId, Comment comment)
{
var article = _repository.Get<Article>(articleId);
_articleService.AddComment(article, comment);
_repository.Save(article);
return RedirectToAction("Index");
}
}
Je cherche donc essentiellement des conseils auprès de personnes plus expérimentées en matière de modélisation de domaines. Si une solution plus évidente m'échappe, faites-le moi savoir :)
Pour être honnête, je n'aime généralement pas les deux solutions, car l'option Service est moins facile à découvrir. Je ne peux plus ajouter un commentaire à une instance d'un article sans disposer d'un ArticleService. Cela semble également moins naturel, puisque AddComment semble être une méthode tellement évidente sur le type Article.
Quoi qu'il en soit, j'ai hâte de lire vos commentaires. Merci d'avance.