public interface Oracle {
String defineMeaningOfLife();
}
위와 같은 비즈니스 메서드가 하나인 인터페이스가 있다고 생각해보자.
위의 경우에는 defineMeaningOfLife()
를 어떻게 정의할 수 있을까?
public class BookwormOracle implements Oracle{
@Override
public String defineMeaningOfLife() {
return "Encyclopedias are a waste of money - go see the world instead";
}
}
위와 같이 정의할 수 있을 것 같다.
그렇다면 위와 같이 매번 반환 값을 일일이 지정하여 반환해야 할까?
그러고 싶지는 않을 것이다.
그럼 어떻게 할 수 있을까?
예시를 통해 알아보자.
public class BookwormOracle implements Oracle{
private Encyclopedias encyclopedias;
public void setEncyclopedias(Encyclopedias encyclopedias) {
this.encyclopedias = encyclopedias;
}
@Override
public String defineMeaningOfLife() {
return encyclopedias.findMean("life");
}
}
위와 같이 정의할 수 있지 않을까?
그렇다면 setEncyclopedias()
를 인터페이스에 미리 지정하면 되는 것 아닐까?
왜 처음에 지정하지 않았을까?
setEncyclopedias()
와 같은 의존성 주입 메서드를 인터페이스에 정의하는 해당 인터페이스의 모든 구현체가 encyclopedias 의존성을 사용하거나 최소한 인지하도록 강제하는 경우에 지정하는 것이 좋다고 한다.
setEncyclopedias()
를 인터페이스에 추가하였다면 아래와 같이 변경할 수 없었을 것이다.
public class BookwormOracle implements Oracle{
private GoogleEngine googleEngine;
public void setGoogleEngine(GoogleEngine googleEngine) {
this.googleEngine = googleEngine;
}
@Override
public String defineMeaningOfLife() {
return googleEngine.findMean("life");
}
}
비즈니스 인터페이스에 의존성 주입을 위해 항상 수정자를 정의하지는 않지만,
구성인자를 정의하는 수정자와 접근자를 두는 것은 좋은 생각이며 수정자 주입을 유용하게 사용할 수 있는 방법이기도 하다.
즉, 구성 인자는 의존성의 특수한 형태로 볼 수 있다.
그럼, 구성 인자와 구성인가 아닌 의존성 사이의 차이점은 무엇인가 하는 의문이 생길 수 있다.
비즈니스 인터페이스 내에서 구성 옵션을 정의할지 말지 고민된다면 구성 인자가 비즈니스 인터페이스의 모든 구현체에서 사용될지, 단 하나의 구현체에서만 사용될지 고려하면 좋다고 한다.
예를 들어 모든 NewsletterSender 구현체는 이메일을 보낼 때 SMTP 서버를 알아야 한다.
하지만 모든 이메일 API가 보안 기능을 지원하지 않으며 대다수 구현체가 보안을 고려하지 않았다고 가정하는 것이 더 정확할 것이므로 보안 이메일을 보낼지 여부를 나타내는 구성 옵션을 인터페이스에서 제외하는 것이 더 좋을 것이다.
수정자 주입을 사용하면 부모 컴포넌트의 인스턴스를 새로 생성하지 않고도 즉시 의존성을 다른 구현체로 교체할 수 있다.