ITEM 5 "자원을 직접 명시하지 말고 의존 객체 주입을 사용하라"
이 ITEM 을 확인하기 전에 위 백기선님의 Effective Java 해설 영상을 보는 것을 추천한다.
열심히 문어체로 정리하고 작성하지만, 구어체를 따라 올 전달력은 없는 것 같다. 열심히 예를 들어 설명해주셔서 덕분에 이해가 잘 됐다.
객체 지향 세계에서 객체들은 독립적이고 자신의 상태를 책임지기 때문에 다른 객체에서 값을 꺼내 사용하기 보다는 직접 그 객체에게 메세지를 보내 처리한다. 그래서 대상 객체에 메세지를 보내기 위해 대상 객체를 내포하고 있다.
class A {
private B b;
}
A 에서 B 로 흐름이 이어지니 A -> B 로 의존성이 있다고 표현한다. 이번 장에서는 이런 의존성을 관계로 맺을 때 직접 객체를 명시하지 말고 DI(Dependency Injection) 를 사용하라고 권장하고 있다.
class A {
// 직접 명시
private final B b = new B();
// DI
private final C c;
public A (C c) { this.c = c; }
}
직접 명시하게 될 경우 B 가 아닌 다른 객체를 테스트해보고 싶을 때 A 라는 클래스를 매번 수정해야 된다는 단점이 있다. 또한 final 지시자를 지우고 다른 메서드에서 b 라는 객체를 다른 객체로 바꾸더라도 멀티 쓰레드 환경에서는 적합하지 않다. 원래 있었던 객체를 다른 객체로 바꾸어도 동작을 보장해야 되는데 불안전하다.
Item 3 과 Item 4 에서 소개한 싱글톤 객체와 유틸 클래스는 한 번 로드가 되면 수정이 불가능하거나 static 한 변수를 사용하기 때문에 위와 같이 직접 명시를 사용한다. 앞에서 살펴보았듯이 유연하지 않으며 사실 두 클래스 모두 객체 지향적인 사고가 아니라는 것을 알 수 있다. 일반적이지 않으니 꼭 필요할 때만 사용해야 한다.
아래 방법처럼 DI 를 사용하면 많은 이점이 있다. 연관된 객체가 여러 개이든 상관 없이 그 추상 객체 하나만 주입 받으면 문제 없이 잘 동작한다. 또한 불변을 보장하여 여러 클라이언트가 의존 객체들을 안심하고 공유할 수 있다. 주입 당시 다른 객체들을 삽입할 수 있으므로 테스트에도 용이하다.
사실, 디자인 패턴의 꽃이라고 불리는 전략 패턴도 사실 이 DI (의존관계, 연관관계) 를 강조한 개념이다.
public class A {
// 스프링 프레임워크 같은 DI 프레임워크에서 지원해주는 필드 주입
@AutoWired
private final B b;
// 생성자 주입
public A(B b) { this.b = b; }
// Setter 주입
public void setB(B b) { this.b = b; }
// 일반 메서드 주입 (Setter 주입과 유사하다.)
public void ilban(B b) { this.b = b; }
// 실제 사용 예시
public static void main(String[] args) {
B b = new B();
A a = new A(b);
}
}
위와 같이 DI 는 생성자 주입, 필드 주입, 수정자 주입, 일반 메서드 주입 등 다양한 곳에서 주입할 수 있다. 필드 주입은 스프링 프레임워크와 같은 DI 프레임워크가 없으면 불가능하며 외부에서 접근이 불가능하다는 단점이 있다. 수정자 주입(Setter)은 주입 받는 객체가 변경될 가능성이 있는 경우에 사용되는데 객체가 변경될 가능성이 극히 드물다.
생성자 주입이 "객체의 불변성 확보", "테스트 코드 작성 용이", "필드 객체에 final 키워드 사용 가능" 이라는 이점들이 많아 제일 많이 사용된다. 생성자 주입을 응용하여 팩토리 메서드 패턴으로 활용할 수도 있다. 자바 8부터 제공해주는 Supplier<T> 함수형 인터페이스를 사용하여 지금 당장 객체를 만들어 주입하지 않더라도, 나중에 주입해줄 수 있게 생성자에 자원 팩토리를 넘겨줄 수도 있다. 타입에 한정적 와일드 카입을 사용한다면 (Supplier<? extends A>) A 클래스의 하위 클래스도 상황에 따라 생성할 수 있는 유연함도 갖추게 된다.
하지만 이러한 주입도 위 코드 실제 사용 예시 보면 주입 한 개당 여러 개의 구문을 작성해야 한다는 단점이 있다. 지금은 한 개 밖에 되지 않지만 의존 관계가 체인 형태로 구성되어 있고 갯수가 많아지면 복잡해지고 관리가 힘들 것이다.
현실적으로 대거, 주스, 스프링 같은 DI 프레임워크를 사용하여 개발할 가능성이 크다. ^^
'독후감 > Effective JAVA' 카테고리의 다른 글
[Effective JAVA] 7 "다 쓴 객체 참조를 해제하라" (0) | 2022.04.28 |
---|---|
[Effective JAVA] 6 "불필요한 객체 생성을 피하라" (0) | 2022.04.28 |
[Effective JAVA] 4 "인스턴스화를 막으려거든 private 생성자를 사용하라" (0) | 2022.04.26 |
[Effective JAVA] 3 "private 생성자나 열거 타입으로 싱글턴임을 보증하라" (0) | 2022.04.26 |
[Effective JAVA] 2 "생성자에 매개변수가 많다면 빌더를 고려하라" (0) | 2022.04.21 |