두 개의 객체가 있을 시, 하나의 객체가 다른 객체를 생성 또는 메소드를 호출할 때, 그 객체를 의존한다고 표현한다.
그럼 왜 이게 문제가 되는건데?
예를 하나 들어보자 어떠한 기존의 어떤 이커머스 쇼핑몰의 할인 정책은 10만원 이상 물건 구매 시 고정적으로 만 원을 할인해준다. 그런데 할인 정책을 10만원 이상 구매 시 총 구매 가격의 5%를 할인해주는 정책으로 바꾸고 싶다.
클라이언트 객체가 고정 할인 객체에 의존할 경우 가격 정책을 바꿀 시 구매를 담당하는 코드에 영향을 준다. DIP를 위반하면 OCP도 같이 위반하게 된다.
해결방법은?
DIP를 위반하지 않게 구매를 담당하는 코드가 인터페이스를 의존하게 만들어준다.
의존관계 주입(Dependency Injection)
외부에서 객체 간의 관계를 결정해주고 인터페이스를 두어 Dependency가 고정되지 않도록 하고 RunTime 시에 관계를 동적으로 주입해 유연성을 확보하고 결합도를 낮춤.
다양한 Dependency Injection 방법
생성자 주입
setter 주입
필드 주입
일반 메서드 주입
의존관계 주입 시 생성자를 이용해야 하는 이유
필드 주입은 코드가 간결하지만 외부에서 변경이 불가능해서 테스트 하기 힘들다는 치명적인 단점이 있다 -> DI 프레임워크가 없는 순수한 자바 코드에서는 아무것도 할 수 없다.
setter 주입을 사용하면 set 메소드를 public으로 열어야 한다. 변경하면 안되는 메서드를 열어두는 것은 좋은 설계 방법이 아니다.
일반 메서드 주입 방식은 테스트 시 어떠한 의존관계 주입이 누락이 될 경우 NullPointerException이 발생한다. 생성자 주입을 사용하면 final 키워드를 사용해 이를 해결할 수 있다.
대부분의 의존관계 주입은 한 번 일어나면 어플리케이션 종료 시점까지 의존 관계를 변경할 일이 없다. 오히려 대부분의 의존관계는 어플리케이션 종료 전까지 불변해야 한다. 생성자 주입은 객체를 생성할 때 딱 한 번만 호출 되므로 이후에 호출할 일이 없다. 즉 불변하게 설계할 수 있다.