티스토리 뷰

반응형

스프링 프레임워크에서 하나의 인터페이스 (혹은 상위 클래스)를 구현(상속)한 여러개의 빈이 존재하고, 그 빈들을 모두 다뤄야 하는 경우에 예제를 보겠습니다.

 

예제로 사용할 빈들은 다음과 같습니다.

public interface Music {
    void playing();
}
@Component
public class Music1 implements Music{
    @Override
    public void playing() {
        System.out.println("뮤직1의 흥겨운 노래");
    }
}
@Component
public class Music2 implements Music{
    @Override
    public void playing() {
        System.out.println("뮤직2의 즐거운 노래");
    }
}
@Component
public class Music3 implements Music{
    @Override
    public void playing() {
        System.out.println("뮤직3의 신나는 노래");
    }
}

하나의 Music 인터페이스를 구현한 별개의 3가지의 구현 클래스가 존재합니다. 그리고 @Component 를 이용하여서 빈(Bean)등록을 하였습니다.

 

방법1. (무식하게) 다 주입받기

만약 Music 인터페이스를 구현한 3가지의 빈을 모두 주입받고 다뤄야 하는 경우 아래와 같이 하나씩 주입 받을 수 있습니다.

@Component
public class MusicPlayer {
    private Music music1;
    private Music music2;
    private Music music3;

    public MusicPlayer(Music music1, Music music2, Music music3) {
        this.music1 = music1;
        this.music2 = music2;
        this.music3 = music3;
    }
    
    ...
}

이런식으로 주입 받게 되어도 사용 할 수 있겠지만 새로운 Music 구현체가 생기게 되는 경우 새로운 Music 구현체를 주입받는 코드와 필드를 추가해야하며, If문이나 switch문으로 분기처리라도 해야되는 상황에서는 끔찍한 코드가 양산되고 말 것입니다. (유식한 말로 개방폐쇄원칙에 어긋난다고 합시다. ㅎㅎ)

 

방법2. (우아하게) 컬렉션으로 주입받기

같은 Music타입의 빈을 모두 주입받고 싶다면, 해당 컬렉션을 다루는 필드를 선언해 주시면 됩니다.

@Component
public class MusicPlayer {
    private final Map<String, Music> musics;

    public MusicPlayer(final Map<String, Music> musics) {
        this.musics = musics;
    }
    
    ...
}

Map<String, Music>을 선언하게 되면 Key값은 빈의 이름이 (= 클래스명 혹은 따로 명시한 이름) 들어가고 value값에는 해당 빈이 들어가게 됩니다. 새로운 Music 클래스 빈이 추가 된다고 하여도 MusicPlayer의 코드를 수정 할 필요가 없으며, 분기문으로 처리하던 일을 Map을 사용하게 되니 성능상에도 큰 이점이 있습니다.

 

(Map을 사용하지 않더라도 Set이나 List도 사용가능합니다.)

반응형
댓글