IoC & DI

Hanjmo·2023년 7월 27일
1

IoC(Inversion of Control)

제어의 역전(IoC)은 "프로그램의 흐름을 객체 스스로 직접 제어하는 것이 아닌 외부에서 관리하는 것"을 의미한다.

제어가 뭘 의미하는데?

제어란 객체를 생성하고 사용하는 등 객체의 생명주기를 직접 관리하는 것을 말한다.

public class OrderServiceImpl implements OrderService {

    private final MemberRepository memberRepository = new MemoryMemberRepository;
    private final DiscountPolicy discountPolicy = new FixDiscountPolicy;

		// ...
}

이렇게 구현 객체가 직접 객체를 관리하는 경우 새로운 할인 정책이 적용되었을 때 코드를 변경해야 하며, 구현 클래스에 의존하고 있기 때문에 DIP를 위반하게 된다.

제어의 역전이란?

제어의 역전은 결국 객체의 생명주기를 역전시켜서 외부에서 관리하는 것을 의미한다.

다음과 같이 AppConfig라는 설정 클래스를 통해서 객체를 관리하며, OrderServiceImpl은 어떤 구현 객체들이 실행될지 모른채 자신의 로직만 실행하면 된다.

class AppConfig {

		@Bean
    public OrderService orderService() {
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

		// ...
}

class OrderServiceImple implements OrderService {
		
    private final MemberRepository memberRepository = new MemoryMemberRepository;
    private final DiscountPolicy discountPolicy = new FixDiscountPolicy;

		public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
		
		// ...
}

IoC를 통해 어떤 효과를 볼 수 있지?

OrderServiceImple 클래스는 직접 구현 객체를 생성하고, 실행하는 다양한 책임을 가지고 있었지만, AppConfig가 구현 객체를 생성하는 책임을 갖게 되면서 SRP를 따를 수 있게 된다.

제어의 흐름을 외부에서 관리하면, 애플리케이션이 크게 사용 영역과 구성 영역으로 분리된다.

RateDiscountPolicy를 FixDiscountPolicy로 수정해도 구성 영역에만 영향을 미치고, 사용 영역에서는 이 사실을 전혀 신경쓰지 않아도 된다.

DI(Dependency Injection)

의존관계 주입(DI)은 "실행 시점에 외부에서 필요한 구현 객체를 생성하여 주입하는 것"을 말한다.

의존관계는 구현 객체가 상호작용하기 위해서 형성된 관계를 말하며, 의존관계 주입은 결국 구현 객체가 어떤 구현 객체를 참조하도록 연결하는 것을 의미한다.

DI의 장점

의존관계 주입을 사용하면 정적인 클래스 코드를 변경하지 않고도 동적인 객체 인스턴스 의존관계를 쉽게 변경할 수 있다.

public class Main {
    public static void main(String[] args) {
        LoginService kakao = new LoginService(new KakaoLogin());
        kakao.login(); // kakao login

        LoginService naver = new LoginService(new NaverLogin());
        naver.login(); // naver login
    }
}

class LoginService {
    private Login login;

    public LoginService(Login login) {
        this.login = login;
    }

    public void login() {
        login.login();
    }
}

class KakaoLogin implements Login {

    @Override
    public void login() {
        System.out.println("kakao login");
    }
}

class NaverLogin implements Login {

    @Override
    public void login() {
        System.out.println("naver login");
    }
}

다양한 의존관계 주입 방법

의존관계를 주입하는 방법에는 생성자 주입, 수정자 주입, 필드 주입 등이 있으며, 불변, 누락의 이유로 거의 생성자 주입을 선택한다.

1개의 댓글

comment-user-thumbnail
2023년 7월 27일

좋은 글이네요. 공유해주셔서 감사합니다.

답글 달기