의존성 주입(DI)의 필요성
의존성 주입(Dependency Injection, DI)
의존성 주입은 소프트웨어 설계 패턴 중 하나로, 객체 간의 의존성을 외부에서 주입하는 방법을 의미합니다. DI는 객체 지향 프로그래밍에서 객체 간의 결합도를 낮추고, 코드의 재사용성과 테스트 용이성을 높이기 위해 사용되고 있습니다.
DI의 필요성
먼저 의존성과 결합도 라는 개념을 이해해야 합니다.
의존성 주입은 소프트웨어 설계 패턴 중 하나로, 객체 간의 의존성을 외부에서 주입하는 방법을 의미합니다. DI는 객체 지향 프로그래밍에서 객체 간의 결합도를 낮추고, 코드의 재사용성과 테스트 용이성을 높이기 위해 사용되고 있습니다.
의존성을 외부에서 주입하지 않고 직접 객체를 생성하면, 코드의 결합도가 높아지게 됩니다. 예를 들어, 아래의 코드를 살펴보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
public class UserService {
private UserRepository userRepository;
public UserService() {
this.userRepository = new UserRepository(); // 직접 객체 생성
}
public void performService() {
// 서비스 로직
}
}
위 코드에서는 UserService 클래스가 UserRepository 객체를 직접 생성하고 있습니다. 이는 UserService가 UserRepository에 강하게 결합되어 있음을 의미합니다. 만약 UserRepository의 구현을 변경해야 한다면, UserService도 함께 변경해야 할 가능성이 큽니다.
예를 들어, UserRepository를 JdbcUserRepository로 변경한다고 가정해보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
public class UserService {
private JdbcUserRepository userRepository;
public UserService() {
this.userRepository = new JdbcUserRepository(); // 변경된 객체 생성
}
public void performService() {
// 서비스 로직
}
}
이 경우, UserRepository를 사용하는 모든 부분을 찾아서 JdbcUserRepository로 변경해야 합니다. 즉, 직접 객체를 생성하면 결합도가 높아지며, 변경 시 많은 부분의 수정이 필요합니다.
DI를 사용한 설계
의존성 주입을 사용하면 결합도를 낮출 수 있습니다. 아래 코드를 살펴보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
public class UserService {
private UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository; // 외부에서 주입
}
public void performService() {
// 서비스 로직
}
}
위 코드에서는 UserRepository를 생성자 매개변수로 받아서 주입하고 있습니다. 이를 통해 UserService는 UserRepository의 구체적인 구현체에 의존하지 않게 됩니다. 이제 UserRepository의 구현체가 변경되더라도 UserService의 코드를 수정할 필요가 없습니다. 예를 들어, JdbcUserRepository로 변경하고 싶다면, 서비스 클래스를 호출하는 부분만 수정하면 됩니다.
1
2
UserRepository userRepository = new JdbcUserRepository();
UserService userService = new UserService(userRepository);
이처럼 의존성 주입을 사용하면 객체 간의 결합도를 낮출 수 있으며, 코드의 변경에 유연하게 대응할 수 있습니다. 또한, 테스트 시에도 목 객체(Mock Object)를 사용하여 유닛 테스트를 보다 용이하게 할 수 있습니다.
직접 객체 생성과 DI 사용의 차이
- 직접 객체 생성 방식
1
private JdbcUserRepository userRepository;
특정 구현체(JdbcUserRepository)를 직접 사용하고, 클래스 필드도 해당 구현체 타입으로 선언합니다.
- 의존성 주입 방식
1
private UserRepository userRepository;
인터페이스(UserRepository) 타입으로 필드를 선언하고, 생성자를 통해 외부에서 구현체를 주입받습니다.