J'ai récemment lu Clean Code et divers articles en ligne sur SOLID, et plus j'en lis, plus j'ai l'impression de ne rien savoir.
Supposons que je construis une application Web à l'aide d'ASP.NET MVC 3. Disons que j'ai un UsersController
avec une Create
action comme celle-ci:
public class UsersController : Controller
{
public ActionResult Create(CreateUserViewModel viewModel)
{
}
}
Dans cette méthode d'action, je veux enregistrer un utilisateur dans la base de données si les données entrées sont valides.
Maintenant, selon le principe de responsabilité unique, un objet devrait avoir une responsabilité unique, et cette responsabilité devrait être entièrement encapsulée par la classe. Tous ses services devraient être étroitement alignés sur cette responsabilité. Étant donné que la validation et l'enregistrement dans la base de données sont deux responsabilités distinctes, je suppose que je devrais créer une classe distincte pour les gérer comme ceci:
public class UsersController : Controller
{
private ICreateUserValidator validator;
private IUserService service;
public UsersController(ICreateUserValidator validator, IUserService service)
{
this.validator = validator;
this.service= service;
}
public ActionResult Create(CreateUserViewModel viewModel)
{
ValidationResult result = validator.IsValid(viewModel);
if (result.IsValid)
{
service.CreateUser(viewModel);
return RedirectToAction("Index");
}
else
{
foreach (var errorMessage in result.ErrorMessages)
{
ModelState.AddModelError(String.Empty, errorMessage);
}
return View(viewModel);
}
}
}
Cela a un certain sens pour moi, mais je ne suis pas du tout sûr que ce soit la bonne façon de gérer des choses comme ça. Il est par exemple tout à fait possible de passer une instance invalide de CreateUserViewModel
à la IUserService
classe. Je sais que je pourrais utiliser les DataAnnotations intégrées, mais que faire quand elles ne suffisent pas? Image que mon ICreateUserValidator
vérifie la base de données pour voir s'il existe déjà un autre utilisateur du même nom ...
Une autre option est de laisser le IUserService
soin de la validation comme ceci:
public class UserService : IUserService
{
private ICreateUserValidator validator;
public UserService(ICreateUserValidator validator)
{
this.validator = validator;
}
public ValidationResult CreateUser(CreateUserViewModel viewModel)
{
var result = validator.IsValid(viewModel);
if (result.IsValid)
{
// Save the user
}
return result;
}
}
Mais je sens que je viole le principe de responsabilité unique ici.
Comment dois-je gérer quelque chose comme ça?
user
classe ne devrait-elle pas gérer la validation? SRP ou non, je ne vois pas pourquoi l'user
instance ne devrait pas savoir quand elle est valide ou non et s'appuyer sur autre chose pour le déterminer. Quelles autres responsabilités la classe a-t-elle? De plus, lorsque lesuser
modifications changent, la validation changera probablement, donc l'externalisation vers une autre classe ne créera qu'une classe étroitement couplée.