재우니의 블로그

 

 

 

Single Responsibility Principle (SRP) 

 

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)
    {
        // 메시지 기록 코드
        // ...

        // 메시지 형식 지정 코드
        // ...

        // 이메일을 통해 메시지 보내기 코드
        // ...
    }
}