😀DI(Dependency Injection)이라는 용어를 아무것도 모르고 봤을 때는 꼭 SQL Injection, CRLF Injection 처럼 해킹 공격 기법이 생각 났다.
하지만 제어의 역전(IoC) 포스팅을 작성하면서 IoC구현 방법 중에 하나로 DI(Denpendency injection)가 있었다.
IoC 포스팅과 OOP 포스팅에도 짧게 설명되어 있지만, 좀 더 자세하게 알아보자
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 해와서 쓰는 경우가 있엇을 것이다.
// 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 모듈을 다른 모듈로 대체하는 것만으로도 로깅 기능을 바꿀 수 있다. 따라서, 코드의 유지보수성과 확장성을 높일 수 있다.
객체지향 프로그래밍(OOP)에서 발생하는 문제를 해결하기 위해 등장하였다.
OOP에서는 객체 간의 결합도를 낮추는 것이 중요하다. 객체가 직접 다른 객체를 생성하거나 관리하는 경우에는 객체 간의 결합도가 높아지므로, 객체의 재사용성과 유지보수성이 떨어지게 된다. 이를 해결하기 위해 DI 패턴이 등장하게 되었다.
😀DI를 구현하는 방법은 아래와 같이 다양하지만, 크게 사용되는 3가지 방식에 대해서만 포스팅 할 것이다.
- 생성자 주입(Constructor Injection)
- Setter 주입(Setter Injection)
- Interface 주입(Interface Injection)
- 필드 주입(Field Injection)
- 메소드 주입(Method Injection)
😀우리는 OOP의 실현과 단점의 보완을 위해 DI를 사용하게 되었고 많은 장점을 가지고 있지만, 한편으로는 단점 또한 생각해 볼 필요가 있다.
객체 간의 결합도를 낮출 수 있다.
의존성 주입을 사용하면 객체 간 결합도를 낮출 수 있습니다. 의존성이 낮으면 코드를 수정하거나 유지보수하는데 용이해진다.
객체의 재사용성과 유지보수성을 향상시킬 수 있다.
로직에서 사용하는 클래스 등의 컴포넌트가 독립적으로 작동시킬 수 있어 코드의 재사용성이 높아진다. 한 클래스를 다른 클래스에서도 쉽게 재사용할 수 있다.
테스트의 용이성이 증가한다.
의존성 주입은 객체를 쉽게 대체할 수 있다. 이렇게 하면 단위 테스트를 쉽게 수행할 수 있다.
코드의 가독성이 향상된다.
코드가 복잡해 질 수있다.
DI를 구현하려면 추가적인 코드가 필요하므로 로직이 길어지고 코드가 복잡해질 수 있다.
객체생성 시간이 늘어날 수 있다.
DI를 구현하려면 객체를 생성하는 데 시간이 걸린다. 또한 객체를 생성할 때마다 다른 객체의 의존성을 주입해야 하므로 실행 시간 오버헤드가 발생할 수 있다.
참고자료(출처)
위키백과 검색결과 [의존성 주입]
gillog 포스팅 [Spring] DI, IoC 정리
큰돌의 터전 유튜브 동영상 [의존성주입과 의존관계역전원칙 ]