ITEM5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라
핵심
- 필드에 자원을 미리 설정하지 않는다
- 객체 내부에서 자원을 직접 생성하거나 고정된 자원에 의존하지 않는다.
- 대신, 객체 생성 시 필요한 자원을 생성자를 통해 외부에서 전달받는다.
- 자원의 개수와 종류에 제한이 없다
- 생성자를 통해 필요한 자원을 얼마든지 넘겨줄 수 있다.
- 예: 데이터베이스 커넥션, 파일 핸들러, 네트워크 클라이언트 등.
- 불변성을 보장하여 안심하고 공유 가능
- 생성 시 전달받은 자원을 변경하지 않도록 설계하여 불변 객체로 만든다.
- 여러 클라이언트가 동시에 객체를 사용하더라도 안정성을 유지할 수 있다.
- 자원 팩터리(팩터리 메서드)를 사용 가능
- 자원을 생성하는 팩터리 메서드(또는 팩터리 클래스)를 생성자에 전달하여, 유연하게 자원을 생성하거나 주입할 수 있다.
장점
- 테스트 용이성: 자원을 외부에서 주입받으므로, 테스트 시 가짜(Mock) 자원을 주입하여 쉽게 테스트할 수 있다.
- 재사용성 증가: 객체 내부에서 자원을 직접 생성하지 않기 때문에, 다양한 자원과 함께 재사용 가능하다.
- 유연성 강화: 자원의 생성과 사용을 분리하여, 자원을 주입받는 객체는 어떤 자원이 주입되었는지 몰라도 동작할 수 있다.
구현 예시 - 텍스트를 출력하는 클래스
- 파일에 데이터를 출력하거나, 콘솔에 데이터를 출력할 수 있는 **출력 도구(PrintStream)**를 주입받는다.
- 내부에서 자원을 생성하지 않으므로, 자원을 변경하려면 생성자에 새로운 자원을 주입하면 된다.
import java.io.PrintStream;
public class TextPrinter {
private final PrintStream output;
public TextPrinter(PrintStream output) {
this.output = output;
}
public void print(String message) {
output.println(message);
}
}
import java.io.FileOutputStream;
import java.io.PrintStream;
public class Main {
public static void main(String[] args) throws Exception {
TextPrinter consolePrinter = new TextPrinter(System.out);
consolePrinter.print("Printing to console");
try (PrintStream fileStream = new PrintStream(new FileOutputStream("output.txt"))) {
TextPrinter filePrinter = new TextPrinter(fileStream);
filePrinter.print("Printing to file");
}
}
}