Spring Boot 강좌 9 : IoC & DI 적용(느슨한 결합)

coldrice99·2024년 10월 8일
0

메모장 프로젝트의 IoC & DI

오늘은 메모장 프로젝트에서 발생한 객체 중복 생성 문제강한 결합 문제를 해결하기 위해 IoC(Inversion of Control)와 DI(Dependency Injection)를 학습했다. 이를 통해 객체의 생성을 관리하고 유지보수성을 높이는 방법을 적용할 수 있었다.

1. 객체 중복 생성 문제

먼저, MemoService 클래스에서 MemoRepository 객체가 여러 메서드에서 중복 생성되는 문제가 있었다. 이는 코드 중복을 초래하고, 비효율적인 리소스 사용으로 이어진다.

예시 코드 (객체 중복 생성 문제):

public class MemoService {

    private final JdbcTemplate jdbcTemplate;

    public MemoService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public MemoResponseDto createMemo(MemoRequestDto requestDto) {
        // DB 저장
        MemoRepository memoRepository = new MemoRepository(jdbcTemplate); // 중복 생성
        // 로직...
    }

    public List<MemoResponseDto> getMemos() {
        // DB 조회
        MemoRepository memoRepository = new MemoRepository(jdbcTemplate); // 중복 생성
        // 로직...
    }

    public Long updateMemo(Long id, MemoRequestDto requestDto) {
        MemoRepository memoRepository = new MemoRepository(jdbcTemplate); // 중복 생성
        // 로직...
    }

    public Long deleteMemo(Long id) {
        MemoRepository memoRepository = new MemoRepository(jdbcTemplate); // 중복 생성
        // 로직...
    }
}

여기서 문제는, MemoRepository 객체가 여러 메서드에서 반복적으로 생성된다는 점이다. 이는 비효율적이며, 유지보수에 어려움을 줄 수 있다.

2. 객체 중복 생성 문제 해결

이 문제를 해결하기 위해 MemoService 클래스에서 MemoRepository 객체를 한 번만 생성하고, 모든 메서드에서 이를 재사용하도록 수정할 수 있다. 생성자를 통해 객체를 주입받는 방식으로, MemoRepository 객체를 재사용함으로써 중복 생성 문제를 해결할 수 있다.

예시 코드 (중복 생성 문제 해결):

public class MemoService {

    // 멤버 변수 선언
    private final MemoRepository memoRepository;

    // 생성자 주입을 통해 MemoRepository를 한 번만 생성
    public MemoService(JdbcTemplate jdbcTemplate) {
        this.memoRepository = new MemoRepository(jdbcTemplate);
    }

    public MemoResponseDto createMemo(MemoRequestDto requestDto) {
        // DB 저장
        Memo saveMemo = memoRepository.save(requestDto);
        return new MemoResponseDto(saveMemo);
    }

    public List<MemoResponseDto> getMemos() {
        // DB 조회
        return memoRepository.findAll();
    }
}

이제 MemoRepository 객체는 한 번만 생성되고, 모든 메서드에서 재사용된다. 이를 통해 코드 중복이 사라지고 유지보수가 쉬워졌다.


3. 강한 결합의 문제

이제 강한 결합 문제에 대해 살펴보자. 강한 결합이란, 하나의 객체가 다른 객체에 강하게 의존하여, 하나의 객체가 변경되면 다른 객체도 함께 변경해야 하는 상황을 말한다. 예를 들어, Controller1Service1 객체를 생성하고, Service1Repository1 객체를 생성하는 방식에서 Repository1의 생성자가 변경되면, Controller1Service1의 코드도 변경해야 한다.

예시 코드 (강한 결합 문제):

public class Controller1 {
    private final Service1 service1;

    public Controller1() {
        this.service1 = new Service1(); // Service1 직접 생성
    }
}

public class Service1 {
    private final Repository1 repository1;

    public Service1() {
        this.repository1 = new Repository1(); // Repository1 직접 생성
    }
}

public class Repository1 { ... }

이 코드에서, 만약 Repository1의 생성자에 DB 접속 정보(ID, PW)를 추가해야 하는 상황이 생기면, Service1Controller1의 코드도 모두 수정해야 한다.


4. 강한 결합 해결 방법

강한 결합 문제를 해결하기 위해 DI(Dependency Injection)를 사용하여 Repository1 객체를 외부에서 주입받도록 수정할 수 있다. 이를 통해 Controller1, Service1에서 Repository1의 생성을 직접 관리하지 않도록 하여, 결합을 느슨하게 만들 수 있다.

예시 코드 (생성자 주입을 통한 해결):

public class Service1 {
    private final Repository1 repository1;

    // 외부에서 Repository1을 주입받음
    public Service1(Repository1 repository1) {
        this.repository1 = repository1;
    }
}

public class Controller1 {
    private final Service1 service1;

    // 외부에서 Service1을 주입받음
    public Controller1(Service1 service1) {
        this.service1 = service1;
    }
}

이제 Repository1의 생성자가 변경되더라도 Controller1Service1은 변경할 필요가 없다. 객체 생성을 외부에서 주입받는 구조로 바뀌면서, 결합이 느슨해졌기 때문이다.


5. 개선 결과

결과적으로, 강한 결합 문제는 느슨한 결합으로 개선되었으며, 각 객체는 외부에서 주입받아 재사용된다. 이를 통해 코드의 유지보수성과 확장성이 크게 향상되었다.

개선된 코드 (MemoController와 MemoService에 적용):

public class MemoController {

    private final MemoService memoService;

    // MemoService를 외부에서 주입받음
    public MemoController(MemoService memoService) {
        this.memoService = memoService;
    }
}

public class MemoService {

    private final MemoRepository memoRepository;

    // MemoRepository를 외부에서 주입받음
    public MemoService(MemoRepository memoRepository) {
        this.memoRepository = memoRepository;
    }
}

이제 MemoControllerMemoServiceJdbcTemplate을 주입받지 않아도 되며, 필요한 객체만 주입받아 재사용할 수 있다.


6. 제어의 역전 (IoC)

제어의 역전(Inversion of Control, IoC)이란, 프로그램의 제어 흐름이 개발자에서 프레임워크(스프링 등)로 전환되는 것을 의미한다. 즉, 객체의 생성을 개발자가 직접 관리하던 기존 방식에서, IoC를 통해 프레임워크가 객체의 생성을 관리하고 주입하는 방식으로 흐름이 역전된다. 이를 통해 더 유연한 구조와 느슨한 결합을 구현할 수 있다.

  • 강한 결합 상태의 메모장 프로젝트는 비효율적인 코드 구성으로 이루어져 있었다.
    • 제어의 흐름은 Controller ⇒ Service ⇒ Repository의 방향으로 진행되었다.
  • 하지만 DI, 즉 의존성 주입을 통해 제어의 흐름이 Repository ⇒ Service ⇒ Controller로 역전됨으로써, 더 효율적인 코드 구조로 바뀌었다.

느낀 점:

IoC와 DI를 적용함으로써, 강한 결합 문제를 느슨한 결합으로 개선할 수 있었다. 이를 통해 객체 간의 의존성을 줄이고, 코드의 유지보수성과 가독성이 크게 향상되었다. 특히, 제어의 역전을 통해 객체 생성을 프레임워크에 위임함으로써 코드가 훨씬 유연하고 효율적으로 동작하는 것을 확인할 수 있었다.


https://github.com/coldrice99/Spring-boot-Lecture2.git

profile
서두르지 않으나 쉬지 않고

0개의 댓글