私は最近、クリーンコードやSOLIDに関するさまざまなオンライン記事を読んでいますが、それについて読むほど、何も知らないように感じます。
ASP.NET MVC 3を使用してWebアプリケーションを構築しているUsersController
としましょう。たとえば、次のCreate
ようなアクションがあるとします。
public class UsersController : Controller
{
public ActionResult Create(CreateUserViewModel viewModel)
{
}
}
そのアクションメソッドでは、入力したデータが有効な場合、ユーザーをデータベースに保存します。
さて、単一の責任の原則に従って、オブジェクトは単一の責任を持つべきであり、その責任はクラスによって完全にカプセル化されるべきです。そのすべてのサービスは、その責任と厳密に一致している必要があります。検証とデータベースへの保存は2つの別々の責任であるため、次のようにそれらを処理するために別々のクラスを作成する必要があると思います。
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
データベースをチェックして、同じ名前の別のユーザーがすでに存在するかどうかを確認する画像...
もう1つのオプションは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
変更が行われると検証が変更される可能性があるため、別のクラスにアウトソーシングすると、密結合されたクラスのみが作成されます。