Khi theo dõi SRP, tôi nên xử lý việc xác thực và lưu các thực thể như thế nào?


10

Gần đây tôi đã đọc Clean Code và nhiều bài báo trực tuyến khác về RẮN, và càng đọc về nó, tôi càng cảm thấy mình không biết gì.

Giả sử tôi đang xây dựng một ứng dụng web bằng ASP.NET MVC 3. Giả sử tôi có UsersControllermột Createhành động như thế này:

public class UsersController : Controller
{
    public ActionResult Create(CreateUserViewModel viewModel)
    {

    }
}

Trong phương thức hành động đó tôi muốn lưu người dùng vào cơ sở dữ liệu nếu dữ liệu được nhập là hợp lệ.

Bây giờ, theo Nguyên tắc Trách nhiệm Đơn lẻ, một đối tượng nên có một trách nhiệm duy nhất và trách nhiệm đó phải được gói gọn trong lớp. Tất cả các dịch vụ của nó nên được liên kết hẹp với trách nhiệm đó. Vì xác thực và lưu vào cơ sở dữ liệu là hai trách nhiệm riêng biệt, tôi đoán tôi nên tạo để tách lớp để xử lý chúng như thế này:

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);
        }
    }
}

Điều đó làm cho một số ý nghĩa với tôi, nhưng tôi không hoàn toàn chắc chắn rằng đây là cách đúng đắn để xử lý những thứ như thế này. Ví dụ, hoàn toàn có thể truyền một thể hiện không hợp lệ CreateUserViewModelcho IUserServicelớp. Tôi biết tôi có thể sử dụng DataAnnotations tích hợp, nhưng khi chúng không đủ thì sao? Hình ảnh mà tôi ICreateUserValidatorkiểm tra cơ sở dữ liệu để xem đã có người dùng khác có cùng tên chưa ...

Một lựa chọn khác là để cho việc IUserServicechăm sóc xác nhận như thế này:

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;
    }
}

Nhưng tôi cảm thấy mình đang vi phạm Nguyên tắc Trách nhiệm duy nhất ở đây.

Làm thế nào tôi nên đối phó với một cái gì đó như thế này?


userLớp học có nên xử lý việc xác nhận không? SRP hay không, tôi không hiểu tại sao usercá thể không nên biết khi nào nó hợp lệ hay không và dựa vào cái gì khác để xác định điều đó cho nó. Lớp học có trách nhiệm gì khác? Thêm vào đó, khi userthay đổi xác nhận có thể sẽ thay đổi, do đó, việc thuê ngoài đó sang một lớp khác sẽ chỉ tạo ra một lớp kết hợp chặt chẽ.
sebastiangeiger

Câu trả lời:


4

Tôi thực sự không nghĩ rằng bạn đang vi phạm Nguyên tắc Trách nhiệm Đơn lẻ trong ví dụ thứ hai của bạn.

  • Các UserServicelớp học chỉ có một lý do gì để thay đổi: nếu có một cần phải thay đổi cách giúp bạn tiết kiệm một người sử dụng.

  • Các ICreateUserValidatorlớp học chỉ có một lý do gì để thay đổi: nếu có một cần phải thay đổi cách bạn xác nhận một người dùng.

Tôi phải thừa nhận rằng việc thực hiện đầu tiên của bạn là trực quan hơn. Tuy nhiên, việc xác thực nên được thực hiện bởi thực thể tạo người dùng. Bản thân người tạo không nên chịu trách nhiệm xác nhận; nó nên giao trách nhiệm cho một lớp trình xác nhận (như trong lần thực hiện thứ hai của bạn). Vì vậy, tôi không nghĩ rằng thiết kế thứ hai thiếu SRP.


1
Đơn-Trách nhiệm-Mô hình? Nguyên tắc, có lẽ?
yannis

Vâng, tất nhiên :) Đã sửa nó!
Guven

0

Dường như với tôi rằng ví dụ đầu tiên là "gần gũi" hơn với SRP thực sự; Trách nhiệm của Bộ điều khiển trong trường hợp của bạn là phải biết cách kết nối mọi thứ và cách vượt qua ViewModel.

Sẽ không có ý nghĩa hơn khi toàn bộ IsValid / ValidationMessages là một phần của chính ViewModel? Tôi đã không hiểu về MVVM, nhưng có vẻ như mẫu Model-View-Presenter cũ, nơi Người thuyết trình xử lý những việc như vậy là ổn vì nó liên quan trực tiếp đến việc trình bày. Nếu ViewModel của bạn có thể tự kiểm tra tính hợp lệ, sẽ không có cơ hội chuyển một cái không hợp lệ sang phương thức Tạo của UserService.


Tôi luôn nghĩ rằng ViewModels phải là DTO đơn giản mà không có quá nhiều logic trong đó. Tôi không chắc mình có nên đặt thứ gì đó như kiểm tra cơ sở dữ liệu trong ViewModel không ...
Kristof Claes

Tôi đoán nó sẽ phụ thuộc vào những gì xác nhận của bạn đòi hỏi; nếu ViewModel chỉ hiển thị IsValidboolean và ValidationMessagesmảng, nó vẫn có thể gọi vào một lớp Trình xác thực và không phải lo lắng về cách thực hiện xác thực. Controller có thể kiểm tra xem ví dụ đầu tiên if (userViewModel.IsValid) { userService.Create(userViewModel); }Về cơ bản các ViewModel nên biết nếu nó là hợp lệ, nhưng không phải như thế nào nó biết đó là hợp lệ.
Wayne Molina
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.