[Effective Java] item5 - 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라

신민철·2023년 4월 10일
1

Effective Java

목록 보기
5/23
post-thumbnail
public class SpellChecker {
	private static final Lexicon dictionary = ...;

	private SpellChecker() {}

	public static boolean isValid(String word) { ... }
	public static List<String> suggesions(String typo) { ... }
}
public class SpellChecker {
	private final Lexicon dictionary = ...;

	private SpellChecker(...) {}
	public static SpellChecker INSTANCE = new SpellChecker(...);

	public boolean isValid(String word) { ... }
	public List<String> suggestions(String typo) { ... }
}

맞춤법 검사기는 많은 언어를 지원해야 한다. 첫 번째 예시는 정적 유틸리티로 구현한 예시, 두번째는 싱글톤으로 구현한 예시이다.

두 방식은 모두 사전이 단 하나만 존재한다고 가정할 때 썩 좋아보이지는 않는다.

일반적으로 생각해볼때 사전은 다양한 언어를 지원하고, 다양한 분야에 따라 적용되는 사전이 다를 수도 있다.

이를 여러 사전에서 사용할 수 있도록 만들어보자.

dictionary 필드에서 final을 제거하면 다른 사전으로 교체할 수 있지만 오류를 내기 쉽고 멀티스레드 환경에서 사용이 불가능하다.

클래스가 여러 인스턴스를 지원해야 함을 생각해봤을 때

인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식이 적합해보인다.

public class SpellChecker {
	private final Lexicon dictionary;

	public SpellChecker(Lexicon dictionary) {
		this.dictionary = Objects.requireNonNull(dictionary);
	}

	public boolean isValid(String word) { ... }
	public List<String> suggestions(String typo) { ... }
}

이 방식은 의존 객체 주입 패턴인데 dictionary라는 딱 하나의 자원만을 사용하지만, 자원이 몇갠지 의존 관계가 어떻든 관계없이 잘 작동한다.

이 방식은 생성자, 정적 팩토리, 빌더 방식에도 적용이 가능하다.

여기서 드는 궁금점이 하나 있다.

의존성이 뭘까?

public class Dependency {
	public SubClass sub;

	public Dependency() {
		this.sub = new SubClass();
		this.sc.print();
	}
}

위 예시처럼 특정 클래스를 내부 변수로 사용하게 될 경우 Dependency 클래스는 SubClass에 의존성이 있다고 말한다.

만약 SubClass의 구성을 바꾸게 된다면 Dependency 클래스도 바꿔야하므로 추가적인 작업으로 비효율이 발생하게 된다.

다음은 기계를 만들어 볼 것이다!

public interface Machine {
	public void assemble();
	public Boolean deliver();
}

공정을 간단화시켜서 조립을 시키고 배송을 해 줄 것이다. 우리가 여러 기계를 만들어 볼 것이다.

public class Car implements Machine {}

public class Airplane implements Machine {}

public class Train implements Machine {}
public class MachineMaker {
	private Machine mc;

	public MachineMaker() {
		this.mc = new Car();
		or
		this.mc = new Airplane();
	}
}

이러한 방식으로 일일히 만들고 있으면 굉장히 힘들 것이다.. 특히 종류가 늘어날수록 말이다

public class MachineMaker {
	private Machine mc;

	public MachineMaker(Machine mc) {
		this.mc = mc;
		this.mc.deliver();
	}
}

직접 의존성이 있는 객체를 생성하는 것이 아니라 생성 과정에서 의존성이 필요한 객체를 인자로 넘겨줌으로써 유연한 코드를 작성할 수 있게 된다!

사실 코드상에서 큰 차이가 있는지는 잘 안보이지만 장점으로 따지자면 재사용성이 매우 증가했고 의존 관계의 클래스가 수정이 되어도 해당 클래스는 바꿀 것이 없을 것이다! 이것을 의존성 주입 이라고 부른다!

생성자에 자원 팩토리 메소드를 넘겨주는 방식도 있는데 이것은 팩토리 메소드 패턴이라고 부른다.

핵심 정리
클래스가 내부적으로 외부 클래스에 의존할 경우 싱글톤, 정적 유틸리티 클래스는 사용하지 않는 것이 좋다. 대신 필요한 자원을 생성자에 넘겨주자. 의존성 주입 방식은 클래스의 유연성, 재사용성, 테스트 용이성을 기가 막히게 개선해준다!

0개의 댓글