Останнім часом я читав чистий код та різні статті в Інтернеті про 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класі. Я знаю, що міг би використовувати вбудовані в DataAnnotations, але що робити, коли їх недостатньо? Зображення, яке 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зміні валідації, ймовірно, зміниться, тож аутсорсинг, який відрізняється від іншого класу, створить лише щільно зв'язаний клас.