เมื่อติดตาม SRP ฉันจะจัดการกับการตรวจสอบและการบันทึกเอนทิตีได้อย่างไร


10

ฉันอ่านClean Codeและบทความออนไลน์มากมายเกี่ยวกับ 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การเปลี่ยนแปลงการตรวจสอบอาจมีการเปลี่ยนแปลงดังนั้นการเอาต์ซอร์ซไปยังคลาสอื่นจะสร้างคลาสที่คู่กันอย่างแน่นหนาเท่านั้น
sebastiangeiger

คำตอบ:


4

ฉันไม่คิดว่าคุณกำลังละเมิดหลักความรับผิดชอบเดียวในตัวอย่างที่สองของคุณ

  • UserServiceชั้นมีเพียงหนึ่งเหตุผลที่จะเปลี่ยนแปลง: หากมีความจำเป็นที่จะต้องเปลี่ยนวิธีการที่คุณจะบันทึกผู้ใช้

  • ICreateUserValidatorชั้นมีเพียงหนึ่งเหตุผลที่จะเปลี่ยนแปลง: หากมีความจำเป็นที่จะต้องเปลี่ยนวิธีการตรวจสอบผู้ใช้

ฉันต้องยอมรับว่าการใช้งานครั้งแรกของคุณง่ายขึ้นกว่าเดิม อย่างไรก็ตามการตรวจสอบควรทำโดยนิติบุคคลที่สร้างผู้ใช้ ผู้สร้างเองไม่ควรรับผิดชอบในการตรวจสอบ ควรมอบหมายความรับผิดชอบให้กับคลาสตัวตรวจสอบความถูกต้องแทน (เช่นในการนำไปใช้ครั้งที่สองของคุณ) ดังนั้นฉันไม่คิดว่าการออกแบบที่สองขาด SRP


1
เดี่ยวรับผิดชอบแบบ? หลักการบางที
yannis

ใช่แน่นอน :) แก้ไขแล้ว!
Guven

0

สำหรับฉันดูเหมือนว่าตัวอย่างแรกคือ "ใกล้" กับ SRP จริง มันเป็นความรับผิดชอบของคอนโทรลเลอร์ในกรณีของคุณที่จะรู้ว่าต้องวางสายอย่างไรและจะส่งต่อไปยัง ViewModel อย่างไร

มันจะไม่มีเหตุผลที่จะมี IsValid / ValidationMessages ทั้งหมดเป็นส่วนหนึ่งของ ViewModel หรือไม่ ฉันไม่ได้ขลุกอยู่กับ MVVM แต่ดูเหมือนว่ารูปแบบ Model-View-Presenter แบบเก่าซึ่งมันก็โอเคที่ผู้นำเสนอจะจัดการสิ่งต่าง ๆ เช่นนั้นเพราะมันเกี่ยวข้องกับการนำเสนอโดยตรง หาก ViewModel ของคุณสามารถตรวจสอบความถูกต้องได้เองจะไม่มีโอกาสส่งผ่านวิธีที่ไม่ถูกต้องไปยังวิธีการสร้างของ UserService


ฉันมักจะคิดว่า ViewModels ควรเป็นเรื่องง่ายของ DTO โดยไม่มีเหตุผลมากเกินไป ฉันไม่แน่ใจว่าฉันควรใส่บางสิ่งบางอย่างเช่นการตรวจสอบฐานข้อมูลใน ViewModel ...
Kristof Claes

ฉันเดาว่ามันจะขึ้นอยู่กับการตรวจสอบของคุณ ถ้า ViewModel เพิ่งเปิดเผยIsValidบูลีนและValidationMessagesอาเรย์มันก็ยังสามารถเรียกใช้ในชั้น Validator และไม่ต้องกังวลเกี่ยวกับวิธีการตรวจสอบการใช้งาน คอนโทรลเลอร์สามารถตรวจสอบได้ว่าอันดับแรกเช่นif (userViewModel.IsValid) { userService.Create(userViewModel); }โดยพื้นฐานแล้ว ViewModel ควรรู้ว่ามันถูกต้องหรือไม่ แต่ไม่ใช่ว่ามันรู้ว่ามันถูกต้องหรือไม่
Wayne Molina
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.