В последнее время я читал « Чистый код» и различные онлайн-статьи о SOLID, и чем больше я читаю об этом, тем больше чувствую, что ничего не знаю.
Допустим, я создаю веб-приложение с использованием ASP.NET MVC 3. Допустим, у меня есть действие UsersController
с таким Create
действием:
public class UsersController : Controller
{
public ActionResult Create(CreateUserViewModel viewModel)
{
}
}
В этом методе действия я хочу сохранить пользователя в базе данных, если введенные данные верны.
Теперь, согласно принципу единой ответственности, объект должен нести единственную ответственность, и эта ответственность должна быть полностью заключена в класс. Все его услуги должны быть тесно связаны с этой ответственностью. Поскольку проверка и сохранение в базе данных являются двумя отдельными обязанностями, я думаю, мне следует создать отдельный класс для их обработки следующим образом:
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);
}
}
}
Это имеет некоторый смысл для меня, но я совсем не уверен, что это правильный способ справиться с такими вещами. Это, например , вполне возможно передать недопустимый экземпляр CreateUserViewModel
в IUserService
классе. Я знаю, что могу использовать встроенные аннотации данных, но что, если их недостаточно? Изображение, которое my ICreateUserValidator
проверяет базу данных, чтобы увидеть, есть ли уже другой пользователь с таким же именем ...
Другой вариант - позволить IUserService
проверке пройти проверку следующим образом:
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;
}
}
Но я чувствую, что нарушаю принцип единой ответственности здесь.
Как я должен иметь дело с чем-то вроде этого?
user
класс не должен обрабатывать проверку? SRP или нет, я не понимаю, почемуuser
экземпляр не должен знать, когда он действителен или нет, и полагаться на что-то другое, чтобы определить это для него. Какие другие обязанности у класса? Кроме того, приuser
изменении валидация, вероятно, изменится, поэтому передача на аутсорсинг другому классу создаст только тесно связанный класс.