[ASP.NET Core] 의존성 역전 원칙 예제(DIP)

참조


목적

  • 의존성 역전 원칙을 보다 쉽게 이해하기 위해서 C# 코드로 예제를 작성하면서 이해합니다.

의존성 역전 원칙을 위반하는 예

  • 먼저, 의존성 역전 원칙을 위반하는 예제 코드입니다.
  • 2개의 열거형과 하나의 Model 클래스를 만드는 것으로 시작하겠습니다.
public enum Gender
{
    Male,
    Female
}

public enum Position
{
    Administrator,
    Manager,
    Executive
}

public class Employee
{
    public string Name { get; set; }
    public Gender Gender { get; set; }
    public Position Position { get; set; }  
}
  • 다음으로 단순히 직원을 추가하는 하나의 하위 수준의 클래스 EmployeeManager 클래스를 생성합니다.
public class EmployeeManager
{
    private readonly List<Employee> _employees;

    public EmployeeManager()
    {
        _employees = new List<Employee>();
    }

    public void AddEmployee(Employee employee)
    {
        _employees.Add(employee);
    }
}
  • 또한, 직원에 대한 일종의 통계 분석을 수행하기 위해 더 높은 수준의 EmployeeStatistics 클래스를 생성하였습니다.
public class EmployeeStatistics
{
    private readonly EmployeeManager _employeeManager;

    public EmployeeStatistics(EmployeeManager employeeManager)
    {
        _employeeManager = employeeManager;
    }

    public int CountFemaleManagers()
    {
        return 1;
    }
}
  • EmployeeManager 클래스 구조에서는 EmployeeStatistics 클래스의 _employee 목록을 사용할 수 있습니다.
  • 따라서 다음과 같이 코드를 추가합니다.
public class EmployeeManager
{
    private readonly List<Employee> _employees;

    public EmployeeManager()
    {
        _employees = new List<Employee>();
    }

    public void AddEmployee(Employee employee)
    {
        _employees.Add(employee);
    }

    public List<Employee> Employees => _employees;
}
  • 이제 EmployeeStatistics 클래스에서 Count 메서드의 로직을 완료할 수 있습니다.
public class EmployeeStatistics
{
    private readonly EmployeeManager _employeeManager;

    public EmployeeStatistics(EmployeeManager employeeManager)
    {
        _employeeManager = employeeManager;
    }

    public int CountFemaleManagers()
    {
        return _employeeManager.Employees.Count(emp => emp.Gender == Gender.Female
                                             && emp.Position == Position.Manager);
    }
}
  • 위의 코드를 동작하게 되면, 정상적으로 동작은 됩니다.
  • 하지만 위 코드는 DIP를 위반한 코드가 됩니다.
  • 위 코드가 DIP를 위반한 이유는 다음과 같습니다.
    • EmployeeStatistics 클래스는 EmployeeManager 클래스와 강한 결합을 갖고 있으며 EmployeeStatistics 생성자에서 EmployeeManager 객체를 제외하고는 다른 객체를 보낼 수 없습니다.
    • 두 번째 문제는 상위 클래스 내부에서 하위 클래스의 공용 속성을 사용하고 있다는 것입니다.

의존성 역전 원칙을 지키는 예

  • 앞에서 작성했던 코드를 DIP를 지켜서 리팩토링 해보도록 하겠습니다.
  • 먼저 EmployeeManager, EmployeeStatistics 2개의 클래스를 분리하여 두 클래스 모두 추상화에 의존하도록 하겠습니다.
  • 따라서 IEmployeeSearchable 인터페이스를 하나 추가하도록 하겠습니다.
public interface IEmployeeSearchable
{
    IEnumerable<Employee> GetEmployeesByGenderAndPosition(Gender gender, Position position);
}
  • 다음으로 EmployeeManager 클래스를 다음과 같이 수정합니다.
public class EmployeeManager : IEmployeeSearchable
{
    private readonly List<Employee> _employees;

    public EmployeeManager()
    {
        _employees = new List<Employee>();
    }

    public void AddEmployee(Employee employee)
    {
        _employees.Add(employee);
    }

    public IEnumerable<Employee> GetEmployeesByGenderAndPosition(Gender gender, Position position)
    {
        return _employees.Where(emp => emp.Gender == gender && emp.Position == position);
    }
}
  • 마지막으로 EmployeeStatistics 클래스도 수정합니다.
public class EmployeeStatistics
{
    private readonly EmployeeManager _employeeManager;

    public EmployeeStatistics(EmployeeManager employeeManager)
    {
        _employeeManager = employeeManager;
    }

    public int CountFemaleManagers()
    {
        return _employeeManager.GetEmployeesByGenderAndPosition(Gender.Female, Position.Manager).Count();
    }
}
  • 이로써 DIP 규칙을 지키는 코드로 변경되었습니다.
  • 이제 EmployeeStatistics 클래스는 하위 수준 클래스에 종속되지 않으며, EmployeeManager 클래스는 Employee 저장에 대한 동작도 변경될 필요가 없습니다.
class Program
{
    static void Main(string[] args)
    {
        var empManager = new EmployeeManager();
        empManager.AddEmployee(new Employee { Name = "Leen", Gender = Gender.Female, Position = Position.Manager });
        empManager.AddEmployee(new Employee { Name = "Mike", Gender = Gender.Male, Position = Position.Administrator });
        var stats = new EmployeeStatistics(empManager);
        Console.WriteLine($"Number of female managers in our company is: {stats.CountFemaleManagers()}");
    }
}
  • 위 처럼 Main 함수를 작성하여 정상적으로 프로그램을 실행할 수 있습니다.
728x90

이 글을 공유하기

댓글

Designed by JB FACTORY