Single Responsibility Principle (SRP): Một class nên chỉ có một lý do để thay đổi (một trách nhiệm duy nhất).
Vi phạm SRP: Class làm quá nhiều việc
// TRƯỚC: Vi phạm SRP
public class InvitationService
{
public 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. Gửi email (phụ thuộc SmtpClient)
var client = new SmtpClient();
client.Send(new MailMessage("test@gmail.com", email)
{
Subject = "Please Join the Party!"
});
}
}
Class này có 3 lý do để thay đổi: quy tắc validate tên, quy tắc validate email, cách gửi email.
Tuân thủ SRP: Tách thành các class nhỏ, mỗi class một trách nhiệm
// SAU: Tuân thủ SRP
// 1. Chỉ lo validate tên
public static class UserNameValidator
{
public static void Validate(string firstName, string lastName)
{
if (string.IsNullOrWhiteSpace(firstName) || string.IsNullOrWhiteSpace(lastName))
throw new Exception("Name is not valid");
}
}
// 2. Chỉ lo validate email
public static class EmailValidator
{
public static void Validate(string email)
{
if (!email.Contains("@") || !email.Contains("."))
throw new Exception("Email is not Valid!");
}
}
// 3. Chỉ lo gửi email
public class EmailSender
{
public void Send(string from, string to, string subject, string body)
{
using var client = new SmtpClient();
client.Send(new MailMessage(from, to) { Subject = subject, Body = body });
}
}
// 4. Orchestrator (coordinator) - chỉ điều phối
public class InvitationService
{
private readonly EmailSender _sender;
public InvitationService(EmailSender sender) => _sender = sender;
public void SendInvite(string email, string firstName, string lastName)
{
UserNameValidator.Validate(firstName, lastName);
EmailValidator.Validate(email);
_sender.Send("test@gmail.com", email, "Please Join the Party!", "Body...");
}
}
Lợi ích
- Dễ hiểu, dễ bảo trì: Mỗi class nhỏ, rõ ràng.
- Dễ test: Mock từng validator, sender riêng biệt.
- Tái sử dụng: Validator dùng được ở nơi khác.
- Giảm coupling: InvitationService không biết chi tiết SMTP.
Dấu hiệu vi phạm SRP
- Class lớn (> 200 dòng), nhiều phương thức không liên quan.
- Nhiều
usingnamespace khác nhau (System.Net.Mail, System.Data.SqlClient...). - Thay đổi một nghiệp vụ làm hỏng nghiệp vụ khác.
- Khó đặt tên class (tên chung chung như Manager, Helper, Service, Processor).
Lưu ý: SRP không có nghĩa là class chỉ có 1 method. Nghĩa là tất cả methods cùng phục vụ một trách nhiệm nghiệp vụ duy nhất.