자원을 직접 명시하지말고 의존 객체 주입을 사용하라. - Effective Java[5]
많은 클래스가 하나 이상의 자원에 의존한다.
객체 지향 프로그래밍에서 클래스간에 의존성이 있다는 것은 클래스간에 의존 관계가 있다는 것을 뜻한다. 즉, 클래스 간에 의존(Dependency) 관계가 있다는 것은 한 클래스가 바뀔 때 다른 클래스가 영향을 받는다는 것을 뜻한다
아래의 예시를 보자.
1 2 3 4 5 6 7 8 | public class Car { private final Engine engine = new Engine(); public static Car INSTANCE = new Car(); private Car() {} //객체 생성 방지용 } | cs |
위 코드에서 Car 클래스는 Engine 클래스에 의존하고 있다.
위 방식은 엔진을 단 하나만 사용한다고 가정한다는 점에서도 그리 훌륭해 보이지는 않는다.
실전에서는 엔진의 종류는 셀 수 없이 많다. 엔진 하나로 모든 쓰임에 대응 할 수 있기를 바라는 건 너무 순진한 생각이다.
Car 클래스가 여러 엔진을 사용할 수 있도록 변경해보자.
간단하게 필드에서 final 한정자를 제거하고 다른 Engine으로 교체 하는 메서드를 추가할 수 있지만, 아쉽게도 이 방식은 어색하고 오류를 내기 쉬우며 멀티스레드 환경에서는 쓸 수 없다.
사용하는 자원에 따라 동작이 달라지는 클래스에는 정적 유틸리티 클래스나 싱글톤 방식이 적합 하지 않다.
그렇다면 어떤 방법을 사용해야 하는가?
클래스(Car)가 여러 자원 인스턴스를 지원해야 하며, 클라이언트가 원하는 자원(Engine)을 사용해야한다.
이 조건을 만족하는 패턴은 바로 의존 객체 주입의 한 형태인 인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식이다.
Step 1 : 자원을 직접 명시하지말고 의존 객체 주입을 사용하라.
1 2 3 4 5 6 7 | public class Car { private final Engine engine; public Car(Engine engine) { this.engine = Objects.requireNonNull(engine); } } | cs |
위 예에서는 engine이라는 딱 하나의 자원만 사용 하지만, 자원이 몇 개든 의존 관계가 어떻든 상관없이 잘 작동한다.
또한 불변을 보장하여 여러 클라이언트가 의존 객체들을 안심하고 공유 할 수 있기도 하다.
의존 객체 주입은 생성자, 정적팩토리, 빌더 모두에 똑같이 응용할 수 있다.
의존 객체 주입이 유연성과 테스트 용이성을 개선해주기는 하지만, 의존성이 수천 개나 되는 큰 프로젝트에서는 코드를 어지럽게 만들기도 한다. 스프링(Spring) 같은 의존 객체 주입 프레임워크 등을 사용하면 이런 어질러짐을 해소 할 수 있다.
정리하자면, 클래스가 내부적으로 하나 이상의 자원에 의존하고, 그 자원이 클래스 동작에 영향을 준다면 싱글톤과 정적 유틸리티 클래스는 사용하지 않는 것이 좋다. 이 자원들을 클래스가 직접 만들게 해서도 안 된다.
대신 필요한 작원을 생성자에 넘겨주자. 의존 객체 주입이라 하는 이 기법은 클래스의 유연성, 재사용성, 테스트 용이성을 기막히게 개선해준다.
참조 - 이펙티브 자바 3/E - 조슈아 블로크
Comments