Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C#

การนำ Single Responsibility Principle ไปใช้ใน C#

Single Responsibility Principle (SRP) คือหลักการที่ว่า "A class should have only one reason to change" (คลาสควรมีเหตุผลเพียงอย่างเดียวที่จะต้องเปลี่ยนแปลง)

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

ตัวอย่าง: ก่อนใช้ SRP (Violation)

public class Program
{
    public static void SendInvite(string email, string firstName, string lastName)
    {
        // 1. Validate Name
        if (string.IsNullOrWhiteSpace(firstName) || string.IsNullOrWhiteSpace(lastName))
            throw new Exception("Name is not valid");

        // 2. Validate Email
        if (!email.Contains("@") || !email.Contains("."))
            throw new Exception("Email is not Valid!");

        // 3. Send Email (SMTP)
        var client = new SmtpClient();
        client.Send(new MailMessage("test@gmail.com", email) 
        { 
            Subject = "Please Join the Party!" 
        });
    }
}

ปัญหา: คลาสนี้มี 3 เหตุผลที่จะเปลี่ยน: 1) เปลี่ยนกฎ Validate Name 2) เปลี่ยนกฎ Validate Email 3) เปลี่ยนวิธีส่งอีเมล (เช่น ใช้ API แทน SMTP)

ตัวอย่าง: หลังใช้ SRP (Compliant)

// 1. รับผิดชอบ Validate Name เท่านั้น
public static class UserNameService
{
    public static void Validate(string firstName, string lastName)
    {
        if (string.IsNullOrWhiteSpace(firstName) || string.IsNullOrWhiteSpace(lastName))
            throw new Exception("Name is not valid");
    }
}

// 2. รับผิดชอบ Validate Email เท่านั้น
public static class EmailService
{
    public static void Validate(string email)
    {
        if (!email.Contains("@") || !email.Contains("."))
            throw new Exception("Email is not Valid!");
    }
}

// 3. รับผิดชอบส่งอีเมล (อาจแยก Interface ออกไปอีกระดับ)
public class EmailSender
{
    public void Send(string from, string to, string subject)
    {
        var client = new SmtpClient();
        client.Send(new MailMessage(from, to) { Subject = subject });
    }
}

// 4. Orchestrator เรียกใช้ Services
public class InvitationService
{
    private readonly EmailSender _emailSender;

    public InvitationService(EmailSender emailSender)
    {
        _emailSender = emailSender;
    }

    public void SendInvite(string email, string firstName, string lastName)
    {
        UserNameService.Validate(firstName, lastName);
        EmailService.Validate(email);
        _emailSender.Send("test@gmail.com", email, "Please Join the Party!");
    }
}

ประโยชน์

  • แต่ละคลาสเล็ก เฉพาะเจาะจง ทดสอบง่าย (Unit Test)
  • ลด Coupling ระหว่างส่วนต่างๆ
  • เปลี่ยนแปลงได้อย่างอิสระ (เช่น เปลี่ยน EmailSender เป็น API ใหม่ ไม่กระทบ Validate)
  • อ่านโค้ดเข้าใจง่าย

ข้อสังเกต

SRP ไม่ได้หมายถึง "คลาสทำได้แค่หนึ่งอย่าง" แต่มีความหมายว่า "มีเหตุผลเปลี่ยนแปลงเพียงอย่างเดียว" คลาสอาจทำหลายอย่างได้ ถ้าสิ่งเหล่านั้นเปลี่ยนแปลงไปพร้อมกันเสมอ (Cohesion สูง)