Recentemente ho letto Clean Code e vari articoli online su SOLID, e più ne leggo, più mi sento come se non sapessi nulla.
Diciamo che sto costruendo un'applicazione web usando ASP.NET MVC 3. Diciamo che ho un UsersController
con Create
un'azione come questa:
public class UsersController : Controller
{
public ActionResult Create(CreateUserViewModel viewModel)
{
}
}
In quel metodo di azione voglio salvare un utente nel database se i dati inseriti sono validi.
Ora, secondo il principio di responsabilità singola, un oggetto dovrebbe avere un'unica responsabilità e tale responsabilità dovrebbe essere interamente incapsulata dalla classe. Tutti i suoi servizi dovrebbero essere strettamente allineati a tale responsabilità. Poiché la convalida e il salvataggio nel database sono due responsabilità distinte, immagino che dovrei creare una classe separata per gestirle in questo modo:
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);
}
}
}
Questo ha un senso per me, ma non sono affatto sicuro che questo sia il modo giusto di gestire cose come questa. Ad esempio, è del tutto possibile passare un'istanza non valida CreateUserViewModel
alla IUserService
classe. So che potrei usare DataAnnotations integrato, ma cosa succede quando non sono sufficienti? Immagine che il mio ICreateUserValidator
controlla nel database per vedere se esiste già un altro utente con lo stesso nome ...
Un'altra opzione è lasciare che IUserService
si occupi della convalida in questo modo:
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;
}
}
Ma sento che sto violando il principio di responsabilità singola qui.
Come dovrei affrontare qualcosa del genere?
user
classe non dovrebbe gestire la validazione? SRP o no, non vedo perché l'user
istanza non dovrebbe sapere quando è valida o meno e fare affidamento su qualcos'altro per determinarlo. Quali altre responsabilità ha la classe? Inoltre, quando leuser
modifiche cambiano, la convalida probabilmente cambierà, quindi l'outsourcing a una classe diversa creerà solo una classe strettamente accoppiata.