Single Responsibility Principle (SRP) 단일 책임 원칙은 "한 클래스는 하나의 책임만 가져야 한다"라는 소프트웨어 디자인 원칙입니다. 쉽게 말해서, 하나의 클래스는 한 가지 일만 해야 하며, 그 일을 잘 수행해야 한다는 원칙입니다. 클래스가 여러 책임을 가지게 되면 코드의 유지보수가 어려워지고 오류가 발생할 가능성이 높아집니다. 이 원칙을 따르면 코드는 모듈화되고 이해하기 쉬워지며, 변경이 필요한 경우 해당 클래스만 수정하면 됩니다
CustomerRepository클래스는 데이터베이스에 고객을 추가하는 역할을 수행하고,EmailService클래스는 고객에게 이메일을 보내는 역할을 수행합니다.
이 코드에서CustomerRepository는 데이터베이스에 고객을 추가하는 책임을 가지고 있고,EmailService는 이메일을 보내는 책임을 가지고 있습니다. 이렇게 하면 두 클래스 각각이 단일 책임을 갖고 있으며, 변경 사항이 발생할 때 해당 클래스만 수정하면 됩니다. 이는 코드를 모듈화하고 이해하기 쉽게 만들며, 예상치 못한 부작용을 줄이는 데 도움이 됩니다.
public class CustomerRepository
{
public void AddCustomer(Customer customer)
{
// 데이터베이스에 고객을 추가하는 코드
Console.WriteLine($"Added customer: {customer.Name}");
}
}
public class EmailService
{
public void SendEmailToCustomer(Customer customer)
{
// 고객에게 이메일을 보내는 코드
Console.WriteLine($"Sent email to customer: {customer.Email}");
}
}
public class Customer
{
public string Name { get; set; }
public string Email { get; set; }
}
class Program
{
static void Main()
{
// 고객 데이터 생성
var newCustomer = new Customer { Name = "John Doe", Email = "john@example.com" };
// CustomerRepository 및 EmailService 인스턴스 생성
var customerRepository = new CustomerRepository();
var emailService = new EmailService();
// 고객 추가
customerRepository.AddCustomer(newCustomer);
// 이메일 보내기
emailService.SendEmailToCustomer(newCustomer);
}
}
SRP 위반된 코드
이 코드에서 CustomerService 클래스는 고객 데이터를 저장하고 동시에 이메일을 보내는 책임을 가지고 있습니다. 이렇게 하면 한 클래스가 두 가지 다른 역할을 수행하고 있어 SRP를 위반하게 됩니다. 만약 이러한 책임 중 하나가 변경된다면 클래스를 수정해야 하며, 이는 예상치 못한 문제를 야기할 수 있습니다. 이렇게 단일 책임 원칙을 위반하는 코드는 유지보수가 어렵고 예측할 수 없는 부작용이 발생할 가능성이 높아집니다.
public class CustomerService
{
public void AddCustomer(Customer customer)
{
// 데이터베이스에 고객을 추가하는 코드
Console.WriteLine($"Added customer: {customer.Name}");
// 동시에 고객에게 이메일을 보내는 코드
SendEmailToCustomer(customer);
}
public void SendEmailToCustomer(Customer customer)
{
// 이메일을 보내는 코드
Console.WriteLine($"Sent email to customer: {customer.Email}");
}
}
public class Customer
{
public string Name { get; set; }
public string Email { get; set; }
}
class Program
{
static void Main()
{
// 고객 데이터 생성
var newCustomer = new Customer { Name = "Jane Doe", Email = "jane@example.com" };
// CustomerService 인스턴스 생성
var customerService = new CustomerService();
// 고객 추가 및 이메일 보내기
customerService.AddCustomer(newCustomer);
}
}
책임 혼합
이 클래스는 같은 메서드 내에서 사용자 인증과 데이터베이스 연결 관리를 결합합니다. 이 예에서UserManager는 SRP를 위반하여 책임을 혼합하고 있습니다. 동일한 메서드 내에서 사용자 인증 및 데이터베이스 연결 관리를 처리하면 클래스가 여러 역할을 담당하게 되어 어느 영역에서 변경이 필요한 경우 잠재적인 문제가 발생할 수 있습니다.
public class UserManager
{
public void AuthenticateUser(string username, string password)
{
// 사용자 인증 코드
// ...
// 데이터베이스 연결 관리 코드
// ...
}
}
불필요한 메서드
OrderProcessingService클래스를 생각해보세요. 이 클래스에는 총 비용 계산 및 이메일 보내기와 같은 관련 없는 작업을 수행하려는 메서드가 있습니다. 이 경우ProcessOrder메서드는 SRP를 위반하며, 관련 없는 책임으로 인해 메서드가 비대해집니다. 대신 특정 책임을 처리하는 별도의 메서드로 분리하는 것이 좋습니다.
public class OrderProcessingService
{
public void ProcessOrder(Order order)
{
// 총 비용 계산 코드
// ...
// 이메일 보내기 코드
// ...
}
}
로깅 과부화
LogManager클래스를 생각해보세요. 이 클래스는 메시지를 기록하고 형식을 지정하며 이메일을 통해 메시지를 보내는 기능을 오버로딩합니다. 이 예에서LogManager클래스는 로깅 기능을 이메일 관련 작업으로 과부하시켜 SRP를 위반합니다. 이는 이해하기 어렵고 수정 및 유지 관리가 어려운 코드로 이어질 수 있습니다. 이러한 관심사를 서로 다른 클래스나 메서드로 분리하는 것이 더 나은 방법입니다.
public class LogManager
{
public void LogMessage(string message)
{
// 메시지 기록 코드
// ...
// 메시지 형식 지정 코드
// ...
// 이메일을 통해 메시지 보내기 코드
// ...
}
}