最近,我一直在阅读Clean Code和各种有关SOLID的在线文章,而我阅读的内容越多,我感觉自己一无所知。
假设我正在使用ASP.NET MVC 3构建Web应用程序。假设我有一个类似这样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
更改时,验证可能会更改,因此将其外包给其他类将仅创建紧密耦合的类。