DI(Dependency Injection)? 의존성 주입이란?

권태형·2023년 3월 16일
0

지식정리

목록 보기
34/72
post-thumbnail

😀DI(Dependency Injection)이라는 용어를 아무것도 모르고 봤을 때는 꼭 SQL Injection, CRLF Injection 처럼 해킹 공격 기법이 생각 났다.

하지만 제어의 역전(IoC) 포스팅을 작성하면서 IoC구현 방법 중에 하나로 DI(Denpendency injection)가 있었다.

IoC 포스팅OOP 포스팅에도 짧게 설명되어 있지만, 좀 더 자세하게 알아보자

의존성 주입(DI)란?

DI (Dependency Injection, 의존성 주입)는 객체 간의 의존성을 런타임 시에 주입하는 디자인 패턴이다.

A클래스가 B클래스를 내부적으로 사용하게 되면 A는 B를 사용하고 사용되는 B가 문제가 발생하거나 변경이 있을 때 A또한 영향을 받는 형태를 "A가 B에 의존한다" 라고 한다. A라는 클래스가 B라는 클래스를 의존한다고 하여도, A라는 클래스는 B의 클래스에 직접 의존하는게 아닌 B의 인터페이스에 의존하게 만드는 것이 의존성 주입이다.

DI를 사용하면 객체가 직접 의존하는 객체를 생성하거나 제어하는 것이 아니라, 외부에서 의존성을 주입받아 사용하게 된다.
이를 통해 객체의 결합도를 낮출 수 있으며, 객체의 재사용성과 유지보수성을 향상시킬 수 있다.

DI는 대부분의 프로그래밍 언어와 프레임워크에서 사용할 수 있다. 특히, Spring 프레임워크에서는 DI를 기본적으로 지원하며, Java에서는 Guice나 Dagger와 같은 DI 프레임워크도 존재한다고 한다.

😀필자는 Java는 아직 써보지 않아서 잘 모르는 부분이지만, 내가 공부한 Javascript의 express는 DI를 기본으로 제공하는 것은 아니지만, 모듈화를 통해 DI를 실현할 수 있다.

우리가 javascript로 작성한 코드들 중에는 다른 파일에서 export해 온 후 사용할 파일에서 import 또는 require 해와서 쓰는 경우가 있엇을 것이다.

Node.js에서 expess의 모듈화로 DI 구현

// logger.js 모듈
module.exports = {
  log: function(message) {
    console.log(message);
  }
};
//app.js
const express = require('express');
const logger = require('./logger.js');

const app = express();
app.get('/', function(req, res) {
  logger.log('Hello, World!');
  res.send('Hello, World!');
});
app.listen(3000);

이렇게 모듈을 이용한 DI를 구현하면, logger 모듈을 다른 모듈로 대체하는 것만으로도 로깅 기능을 바꿀 수 있다. 따라서, 코드의 유지보수성과 확장성을 높일 수 있다.


DI의 등장배경

객체지향 프로그래밍(OOP)에서 발생하는 문제를 해결하기 위해 등장하였다.
OOP에서는 객체 간의 결합도를 낮추는 것이 중요하다. 객체가 직접 다른 객체를 생성하거나 관리하는 경우에는 객체 간의 결합도가 높아지므로, 객체의 재사용성과 유지보수성이 떨어지게 된다. 이를 해결하기 위해 DI 패턴이 등장하게 되었다.


DI의 구현 방법

😀DI를 구현하는 방법은 아래와 같이 다양하지만, 크게 사용되는 3가지 방식에 대해서만 포스팅 할 것이다.

  • 생성자 주입(Constructor Injection)
  • Setter 주입(Setter Injection)
  • Interface 주입(Interface Injection)
  • 필드 주입(Field Injection)
  • 메소드 주입(Method Injection)

1. 생성자 주입(Constructor Injection)

  • 생성자 주입은 의존성 주입을 받을 객체를 클래스 생성자의 매개변수로 받는 방법이다.
    이 방법은 생성자를 통해 의존성을 주입받는 방식으로, 클래스 인스턴스를 생성할 때 의존성을 전달한다.
    코드가 간결해지고, 객체 생성 시점에 의존성을 모두 확인할 수 있어서 안정적인 코드를 작성할 수 있다.

2. Setter 주입(Setter Injection)

  • Setter 주입은 의존성 주입을 받을 객체를 클래스의 Setter 함수를 통해 주입하는 방법이다.
    생성자 주입과 유사하게, 세터 메소드를 통해 의존성을 주입받는 방식이며, 클래스 인스턴스 생성 후에 세터 메소드를 호출하여 의존성을 전달한다. 생성자를 통해 의존성을 주입하면 변경이 불가능하지만, Setter 함수를 사용하면 객체 생성 후에도 의존성을 변경할 수 있다.

3. Interface 주입(Interface Injection)

  • Interface 주입은 객체가 인터페이스를 구현하는 경우 인터페이스를 통해 의존성을 주입하는 방법이라고 한다.
    DI 컨테이너가 객체에 대해 구현해야 할 인터페이스를 제공하고, 객체는 해당 인터페이스를 구현하는 방식으로 DI를 수행한다.
    자바(Java)나 C# 등의 언어에서 주로 사용된다.

DI의 장단점

😀우리는 OOP의 실현과 단점의 보완을 위해 DI를 사용하게 되었고 많은 장점을 가지고 있지만, 한편으로는 단점 또한 생각해 볼 필요가 있다.

장점

  • 객체 간의 결합도를 낮출 수 있다.
    의존성 주입을 사용하면 객체 간 결합도를 낮출 수 있습니다. 의존성이 낮으면 코드를 수정하거나 유지보수하는데 용이해진다.

  • 객체의 재사용성과 유지보수성을 향상시킬 수 있다.
    로직에서 사용하는 클래스 등의 컴포넌트가 독립적으로 작동시킬 수 있어 코드의 재사용성이 높아진다. 한 클래스를 다른 클래스에서도 쉽게 재사용할 수 있다.

  • 테스트의 용이성이 증가한다.
    의존성 주입은 객체를 쉽게 대체할 수 있다. 이렇게 하면 단위 테스트를 쉽게 수행할 수 있다.

  • 코드의 가독성이 향상된다.

단점

  • 코드가 복잡해 질 수있다.
    DI를 구현하려면 추가적인 코드가 필요하므로 로직이 길어지고 코드가 복잡해질 수 있다.

  • 객체생성 시간이 늘어날 수 있다.
    DI를 구현하려면 객체를 생성하는 데 시간이 걸린다. 또한 객체를 생성할 때마다 다른 객체의 의존성을 주입해야 하므로 실행 시간 오버헤드가 발생할 수 있다.


참고자료(출처)
위키백과 검색결과 [의존성 주입]
gillog 포스팅 [Spring] DI, IoC 정리
큰돌의 터전 유튜브 동영상 [의존성주입과 의존관계역전원칙 ]

profile
22년 12월 개발을 시작한 신입 개발자 ‘권태형’입니다. 포스팅 하나하나 내가 다시보기 위해 쓰는 것이지만, 다른 분들에게도 도움이 되었으면 좋겠습니다. 💯컬러폰트가 잘 안보이실 경우 🌙다크모드를 이용해주세요.😀 지적과 참견은 언제나 환영합니다. 많은 댓글 부탁드립니다.

0개의 댓글