Dependency Injection (의존성 주입) 이 뭘까요?

devhong·2023년 1월 3일
0

Dependency Injection (의존성 주입)

  • 하나의 객체가 다른 객체의 의존성을 제공하는 테크닉
  • 객체 간의 결합을 느슨하게 하기 위한 디자인 패턴

Inversion of Control (IoC)

  • 코드 구현 내부에서 의존성이 정해졌다면 프레임워크, 코드 외부의 설정 파일 등을 통해 의존성을 제어할 수 있게 되는 것
  • '제어의 역전' 이라고 불린다.

예를 들어, Object AObject B 를 가진 Client 를 만든다면 기존에는 아래와 같다.

Object A, Object B 생성 -> Object A, Object B 를 이용하여 Client 생성

Dependency Injection 을 이용한다면 아래와 같이 순서가 바뀐다.

비어있는 Client 생성 -> Object A, Object B 생성 -> ClientObject AObject B주입

여기서 주입은 프레임워크를 통해 수행한다.


Example

개발환경 - C# (Visual Studio)

using ProjectA;

class DIMain
{
    public void Test1()
    {
        ProjectATest projectA = new ProjectATest();
        projectA.Test();
    }

    public void Test2()
    {
        ProjectATest projectA = new ProjectATest();
        projectA.Test();
    }

    public void Test3()
    {
        ProjectATest projectA = new ProjectATest();
        projectA.Test();
    }
    public void Test4()
    {
        ProjectATest projectA = new ProjectATest();
        projectA.Test();
    }
}

DIMain 클래스는 ProjectATest 클래스에 의존하게 되므로 ProjectA 클래스를 ProjectB 클래스로 변경하면 모두 변경해줘야 한다.

using ProjectA;

class DIMain
{
    private ProjectATest _project;

    public DIMain()
    {
        _project = new ProjectATest();
    }

    public void Test1()
    {
        _project.Test();
    }

    public void Test2()
    {
        _project.Test();
    }

    public void Test3()
    {
        _project.Test();
    }
    public void Test4()
    {
        _project.Test();
    }
}

그렇다면 위와 같이 생성자를 통해서 어느 정도의 타이트한 관계를 느슨하게 개선할 수 있다.
하지만 Dependency InjectionIoC 를 고려해본다면 현재 동작하는 DIMain 클래스 내부에서가 아닌 외부에서 의존성을 주입해주고자 더 개선하고자 한다.

using ProjectA;
using ProjectB;
using Microsoft.Extensions.DependencyInjection;

// collection 을 통해 ProjectTest Interface와 ProjectTest 클래스 의존성을 주입한다.
ServiceCollection collection = new ServiceCollection();

// 두 번째 인자에 ProjectATest, ProjectBTest 를 선택만 한다면 해당 소스 내 다른 코드들은 수정하지 않아도 된다!
collection.AddScoped<IProjectTest, ProjectBTest>();

// 직접 실행하기 위해 DIMain 클래스를 collection 에 추가한다.
collection.AddScoped<DIMain>();

// BuildServiceProvider() 메소드를 통해 provider 를 생성하고 GetService 로 DIMain 객체를 생성한다.
ServiceProvider provider = collection.BuildServiceProvider();
DIMain diMain = provider.GetService<DIMain>();

diMain.Test1();

class DIMain
{
    private IProjectTest _project;

    public DIMain(IProjectTest project)
    {
        _project = project;
    }

    public void Test1()
    {
        _project.Test();
    }

    public void Test2()
    {
        _project.Test();
    }

    public void Test3()
    {
        _project.Test();
    }
    public void Test4()
    {
        _project.Test();
    }
    
    public static void Main()
    {

    }
}

따라서 적절하게 InterfaceDependency Injection 을 이용한다면 좀 더 느슨해진 객체 간의 관계를 만들어갈 수 있다.

  • Dependency Injection 이 고려되지 않는다면 객체 간의 관계가 타이트해지면서 (= 의존성이 클수록) 수정 사항이 발생하게 되면 코드들을 모두 수정해줘야 한다.
  • 즉, 고려되지 않는다면 유지보수 측면에서 큰 악영향을 끼칠 수 있다.

하면 왜 좋을까?

  • 유지관리 및 코드 재사용성 향상
  • 객체 간 독립성을 유지하므로 유닛 테스트 용이
  • 객체 간 느슨한 결합으로 인하여 코드 수정의 파급 효과가 줄어듬 (생산성 향상)

Reference

profile
당신을 한 줄로 소개해보세요.

0개의 댓글