Tengo un escenario común en el que estoy buscando orientación de personas con más experiencia con DDD y Modelado de dominios en general.Cómo evitar los modelos de dominio anémicos, o cuándo mover los métodos de las entidades a los servicios
Digamos que comienzo a construir un motor de blog, y el primer requisito es que después de que se publique un artículo, los usuarios puedan comenzar a publicar comentarios en él. Esto comienza bien, y conduce a la siguiente diseño:
public class Article
{
public int Id { get; set; }
public void AddComment(Comment comment)
{
// Add Comment
}
}
Mi controlador MVC está diseñado de esta manera:
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");
}
}
Ahora todo funciona bien, y que cumple con el requisito. La siguiente iteración obtenemos el requisito de que cada vez que se publique un comentario, el autor del blog debería recibir un correo electrónico notificándolo.
En este punto, tengo 2 opciones que se me ocurren. 1) Modificar artículo para requerir un servicio de correo electrónico (¿en el controlador?) U obtener un servicio de correo electrónico desde una referencia estática a mi contenedor DI
1a) Parece bastante feo. Creo que rompe algunas reglas del modelo de dominio que mis entidades conocen de los servicios.
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) También parece feo, ahora necesito un contenedor DI configurado al que se accede estáticamente.
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) Crear un IArticleService y mover el método AddComment() para este servicio en lugar de en el propio artículo Entidad.
Esta solución es más limpia, creo, pero Agregar un comentario ahora es menos reconocible y requiere un ArticleService para realizar el trabajo. Parece que AddComment debería pertenecer a la clase de artículo en sí.
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");
}
}
Así que básicamente busco consejos de personas con más experiencia en el modelado de dominios. Si me falta una solución más obvia, por favor hágamelo saber :)
Por lo general, no me gustan las dos soluciones para ser sincero, porque la opción de Servicio es menos reconocible. Ya no puedo agregar un Comentario a una instancia de un Artículo sin tener un ArtículoServicio disponible. También se siente menos natural, ya que AddComment parece ser un método tan obvio en el tipo de artículo.
De todos modos, espero leer la entrada. Gracias por adelantado.
1 para la solución # 2 – JuanZe
1 para una pregunta clara – Rippo