Czytam ostatnio Clean Code i różne artykuły online o SOLID, a im więcej o tym czytam, tym bardziej czuję, że nic nie wiem.
Załóżmy, że buduję aplikację internetową przy użyciu ASP.NET MVC 3. Powiedzmy, że mam UsersController
taką Create
akcję:
public class UsersController : Controller
{
public ActionResult Create(CreateUserViewModel viewModel)
{
}
}
W tej metodzie działania chcę zapisać użytkownika w bazie danych, jeśli wprowadzone dane są prawidłowe.
Teraz, zgodnie z zasadą pojedynczej odpowiedzialności, obiekt powinien ponosić jedną odpowiedzialność, a ta odpowiedzialność powinna być całkowicie zamknięta w klasie. Wszystkie jego usługi powinny być ściśle dostosowane do tej odpowiedzialności. Ponieważ sprawdzanie poprawności i zapisywanie w bazie danych to dwa odrębne obowiązki, myślę, że powinienem utworzyć osobną klasę, aby obsługiwać je w następujący sposób:
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);
}
}
}
To sprawia, że jakiś sens dla mnie, ale ja nie jestem wcale pewien, że to jest właściwy sposób obsłużyć takie rzeczy. Przykładowo jest całkowicie możliwe, aby przejść nieprawidłową instancję CreateUserViewModel
do IUserService
klasy. Wiem, że mogę skorzystać z wbudowanych DataAnnotations, ale co, jeśli nie są wystarczające? Obraz, który mój ICreateUserValidator
sprawdza w bazie danych, aby sprawdzić, czy jest już inny użytkownik o tej samej nazwie ...
Inną opcją jest pozwolenie na IUserService
zajęcie się walidacją w następujący sposób:
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;
}
}
Ale czuję, że naruszam tutaj zasadę pojedynczej odpowiedzialności.
Jak mam sobie z tym poradzić?
user
klasa nie powinna obsłużyć weryfikacji? SRP czy nie, nie rozumiem, dlaczegouser
instancja nie powinna wiedzieć, kiedy jest poprawna czy nie, i polegać na czymś innym, aby to ustalić. Jakie inne obowiązki ma klasa? Plus, kiedyuser
zmiany prawdopodobnie się zmienią, więc outsourcing, że do innej klasy stworzy tylko ściśle powiązaną klasę.