EEALL@ONCE

🔦 의존성 주입이 뭔데 도대체 ? 본문

분류없음지식🔦

🔦 의존성 주입이 뭔데 도대체 ?

올엣원스 2023. 12. 4. 22:35
728x90

의존성 주입(Dependency Injection)은 객체 간의 결합도를 낮추고 유연성을 향상시키기 위한 디자인 패턴 중 하나입니다. 주로 Spring 프레임워크에서 많이 사용되는데, 이는 객체 간의 의존 관계를 외부에서 주입하여 객체가 직접 의존 객체를 생성하지 않도록 하는 것을 의미합니다.

간단한 예시로 Service와 Mapper 클래스를 통한 의존성 주입을 설명해보겠습니다. 예를 들어, Spring 프레임워크를 사용하는 상황을 가정해볼게요.

1. **일반적인 경우 (의존성 주입을 사용하지 않은 경우):**

// UserService 클래스
public class UserService {
    private UserMapper userMapper = new UserMapper();

    public void createUser(User user) {
        // UserService의 로직
        userMapper.insertUser(user);
    }
}

// UserMapper 클래스
public class UserMapper {
    public void insertUser(User user) {
        // UserMapper의 로직
    }
}



위의 코드에서 UserService는 UserMapper에 의존하면서 직접 UserMapper를 생성하고 사용합니다.

2. **의존성 주입을 사용한 경우:**

// UserService 클래스 (의존성 주입 사용)
public class UserService {
    private UserMapper userMapper;

    // 생성자를 통한 의존성 주입
    public UserService(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    public void createUser(User user) {
        // UserService의 로직
        userMapper.insertUser(user);
    }
}

// UserMapper 클래스
public class UserMapper {
    public void insertUser(User user) {
        // UserMapper의 로직
    }
}



여기서 UserService는 생성자를 통해 UserMapper를 주입받습니다. 이렇게 하면 UserService는 외부에서 UserMapper를 주입받아 사용하므로, 의존성이 외부에서 해결되고 결합도가 낮아지게 됩니다.

이러한 구조는 테스트 용이성이나 코드의 유지보수 측면에서 유리합니다. 예를 들어, UserService를 테스트할 때 실제 DB에 연결되는 UserMapper 대신 MockUserMapper 등을 주입하여 테스트할 수 있습니다. 또한, UserMapper가 변경되더라도 UserService에 직접적인 영향을 주지 않고 외부에서 주입된 객체만 바꿔주면 되므로 시스템이 더 유연해집니다.

 


****추가 ****

< 이해가 쉬운 버전 ? >  

의존성 주입은 마치 레고 블록을 조립하는 것과 비슷해. 레고 블록은 각각의 부분이 다른 블록과 함께 동작할 수 있도록 만들어져 있어. 예를 들어, 네가 로봇을 만든다고 상상해봐. 로봇을 동작시키려면 여러 부품들이 필요하지?

의존성 주입은 이 부품들을 조립할 때 사용돼. 각 부품은 독립적으로 만들어지고, 로봇을 만들 때 필요한 부품들을 따로 만들어놓고 조립할 때 넣어주는 거야. 그럼 로봇이 더 쉽게 업그레이드되거나 변경될 수 있어. 만약에 새로운 기능을 추가하거나 다른 부품으로 교체하려면 그냥 필요한 부품만 새로운 것으로 바꾸면 돼.

이게 의존성 주입이야! 그런데 이렇게 부품들을 조립할 때, 각 부품끼리 서로 어떻게 동작하는지 잘 알아야 돼. 그래야 로봇이 올바르게 동작할 수 있어. 이 부분은 마치 각 부품끼리 어떻게 맞물려야 하는지 알려주는 조립 설명서 같아.

코드에서도 이와 비슷한 개념이 적용돼. 프로그램을 만들 때 각 모듈을 독립적으로 개발하고, 필요한 부분끼리 연결해서 사용하게 되는 거야. 이게 의존성 주입이라고 생각하면 돼!


간단한 예제 추가 

동물을 나타내는 클래스가 있고, 그 동물이 소리를 내도록 하는 기능을 추가하고 싶다고 가정해보자.

먼저, 동물을 나타내는 인터페이스와 그 인터페이스를 구현한 클래스를 만들어보자:



이제, 소리를 내도록 하는 기능을 추가하는 클래스를 만들어보자:



여기서 `SoundMaker` 클래스가 `Animal` 인터페이스에 의존하고 있어. 생성자를 통해 `Animal`의 구현체를 주입받고 있다. 이렇게 하면 `SoundMaker`는 어떤 종류의 동물이든 소리를 내도록 할 수 있게 돼.

사용하는 쪽에서는 다음과 같이 사용할 수 있어:



이렇게 하면 `SoundMaker` 클래스는 어떤 동물이든 소리를 내도록 할 수 있고, 새로운 동물을 추가하거나 기능을 변경하기가 쉬워진다. 이게 의존성 주입이 독립성을 어떻게 높여주는지를 보여주는 간단한 예제야.


🧐 그럼 같은 예로 의존성 주입을 하지 않았을 때 독립성이 떨어지는 코드를 보여줘

이 코드에서는 SoundMaker 클래스가 직접 Animal 클래스를 생성하고 사용하고 있어. 이것은 의존성이 강하게 결합되어 있어서 변경이 어려울 수 있어.


🧐 만약에 다른 동물의 소리를 내도록 하고 싶다면 Animal 클래스의 코드를 수정해야 하고, -> 이걸 예로 보여줘

여기서 SoundMaker 클래스에는 makeCatSound라는 메서드가 추가되어 새로운 동물의 소리를 내도록 구현 ...


🧐 의존성 주입을 사용하면 얼마나 독립성이 강해지는지 보자

 

이제 SoundMaker 클래스가 직접 Animal 클래스를 생성하지 않고, 생성자를 통해 주입받도록 변경 ->

이렇게 하면 SoundMaker는 어떤 종류의 동물이든 받아서 소리를 내도록 할 수 있게 됨

 

==========================================================================

즉 내가 이해한 바로는 의존성 주입이란 

각자 할 일을 잘하고, 각자 알아서 수정해서, 서로에게 영향을 최대한 덜 끼치자의 차원의 개념이고

그걸 어떤식으로 진행하냐면, 

각자 할 일을 끝낸 상태로 서로에게 주입이 되는거다. 

예를 들어, 동물 클레스는 각자 동물이 어떤 소리를 낼 지 , 어떤 동물인지를 잘 끝내 놓고

소리내는 클래스에서는 그냥 그 동물을 받아와서 "출력"만 수행하면 되는거다.

어떤 동물인지에 따라 다른 메소드를 쓰는게 아니라 

 

고양이도 소리내기 매소드를 타고 개도 소리내기 매소드만 타면 되는거다무슨 소리를 낼지는 고양이가 알아서 정해서 오는거고, 개도 알아서 정해서 오는거다. 그게 바로 내가 이해한 의존성 주입이다. 

 

==========================================================================

728x90