• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

강의를듣다보니 궁금증이생겼습니다

21.01.03 21:07 작성 조회수 236

14

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

으로하셨는대
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class); 이렇게 하지 않으신 이유가 궁금합니다 이전까지는 이방법으로 했기때문에 궁금해졌습니다

답변 1

답변을 작성해보세요.

40

안녕하세요. dhkdrb897님

ApplicationContext는 AnnotationConfigApplicationContext의 상위 인터페이스 입니다.

그래서 ApplicationContext는 기능이 적고, AnnotationConfigApplicationContext는 너무 많은 기능을 제공합니다.

우리가 개발을 할 때는 가급적 기능을 적게 제공하는 상위 인터페이스를 사용해야, 향후 구현 클래스가 변경되어도 클라이언트 코드를 변경하지 않아도 됩니다. 그래서 실제 스프링 애플리케이션을 개발할 때는 ApplicationContext를 사용합니다. 그런데 스프링 코어를 설명하다보니 AnnotationConfigApplicationContext를 통해서 제공되는 기능들도 필요해서 이렇게 중간에 변경하게 되었습니다.

감사합니다.

hi님의 프로필

hi

2023.06.03

"상위 인터페이스를 사용해야, 향후 구현 클래스가 변경되어도 클라이언트 코드를 변경하지 않아도 됩니다."에서 구현 클래스가 변경되는 예시나 클라이언트 코드가 변경되는 예시를 알 수 있을까요??

안녕하세요. hi님

우선 이 부분은 객체지향에 대한 이해가 필요합니다. 구체적인 예시를 드릴게요.

우리가 음악 플레이어 프로그램을 개발하고 있다고 생각해봅시다. 이 음악 플레이어에서는 MP3, WAV, FLAC 등 다양한 형태의 오디오 파일을 재생할 수 있어야 합니다. 이를 위해 각각의 형식에 대한 재생기능을 가진 클래스를 만들어야 하며, 각각의 클래스를 "구현 클래스"라고 부릅니다.

먼저 인터페이스를 정의합니다:

public interface AudioPlayer {

    void play();

}

그런 다음, 각각의 오디오 파일 형식에 대해 AudioPlayer 인터페이스를 구현하는 구현 클래스를 만듭니다:

public class Mp3Player implements AudioPlayer {

    @Override

    public void play() {

        // MP3 재생 코드

    }

}

public class WavPlayer implements AudioPlayer {

    @Override

    public void play() {

        // WAV 재생 코드

    }

}

public class FlacPlayer implements AudioPlayer {

    @Override

    public void play() {

        // FLAC 재생 코드

    }

}

 

이제 클라이언트 코드에서는 특정한 형식의 오디오 파일을 재생하기 위해 해당 파일 형식의 플레이어를 사용하게 됩니다.

public class ClientCode {

    public void playAudioFile(AudioPlayer player) {

        player.play();

    }

}

여기서 playAudioFile 메소드는 AudioPlayer 인터페이스의 play 메소드를 호출합니다. 따라서 Mp3Player, WavPlayer, FlacPlayer 중 어느 것이 인자로 주어지더라도 이 메소드는 올바르게 작동합니다.

이제 향후에 새로운 오디오 파일 형식, 예를 들어 AAC를 지원하고 싶다면, 단지 AudioPlayer를 구현하는 AacPlayer 클래스만 추가하면 됩니다.

public class AacPlayer implements AudioPlayer {

    @Override

    public void play() {

        // AAC 재생 코드

    }

}

이렇게 되면, 클라이언트 코드는 AAC 파일을 재생할 수 있는 AacPlayer 객체를 만들어 playAudioFile 메소드에 전달하면 되고, 클라이언트 코드 자체는 전혀 변경될 필요가 없습니다.

이러한 방식은 디자인 원칙 중 하나인 개방-폐쇄 원칙(OCP, Open-Closed Principle)에 따른 것입니다. 이 원칙은 "소프트웨어 구성요소(클래스, 모듈, 함수 등등)는 확장에 대해서는 열려있어야 하지만, 변경에 대해서는 닫혀 있어야 한다"는것을 말합니다. 이 경우에, 새로운 오디오 파일 형식의 지원(확장)은 쉽게 추가할 수 있지만, 기존의 클라이언트 코드는 그대로 유지(변경 없음)됩니다.

이 시나리오에서 Mp3Player 같은 것들을 인터페이스로 만들고 Mp3PlayerImpl을 구체 클래스로 만든다고 가정한다면 ClientCode가 Mp3Player에 의존하게되면 향후 다른 것으로 변경시 ClientCode를 변경해야 합니다. 하지만 ClientCode가 AudioPlayer에 의존한다면 변경에 더 유연하게 대응할 수 있겠지요?

감사합니다.

박동규님의 프로필

박동규

2024.03.05

안녕하세요 영한님. 질문이 있습니다.

그렇다면 AnnotationConfigApplicationContext의 getBeanDefinition의 메서드는 ApplicationContext 인터페이스에서 정의한 메서드는 아니지만 AnnotationConfigApplicationContext 클래스에서 추가적으로 정의한 메서드이기 때문에 AnnotationConfigApplicationContext 형으로 ac 인스턴스를 선언한 건가요?

네 동규님 생각하신 내용이 맞습니다.

감사합니다.