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