스프링 핵심원리 - 기본편(스프링 컨테이너와 스프링 빈 2/2)
부모 타입으로 조회
컨테이너에서 특정 Bean을 조회할 때, 상속관계에 대해서 조회하려고 하는 Bean과 이 객체를 상속받는 모 든 Bean을 동시에 조회한다. 아래 코드는 테스트를 위해 만든 TestConfig 클래스이다.
@Configuration
static class TestConfig {
@Bean
public DiscountPolicy rateDiscountPolicy() {
return new RateDiscountPolicy();
}
@Bean
public DiscountPolicy fixDiscountPolicy() {
return new FixDiscountPolicy();
}
}
이 TestConfig를 통해 컨테이너를 생성하면 DiscountPolicy를 상속받는 구현 객체 RateDiscountPolicy와 FixDiscountPolicy가 각각 Bean으로 등록된다.
이에 대해 ac.getBean() 메소드를 통해 DiscountPolicy 타입으로 조회를 시도하면NoUniqueBeanDefinitionException 이 발생한다. 아래는 이에대한 테스트 코드이다.
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
@Test
@DisplayName("부모 타입으로 조회시 자식이 둘 이상 있으면 중복 오류가 발생한다.")
void findBeanByParentTypeDuplicate(){
Assertions.assertThrows(NoUniqueBeanDefinitionException.class,()-> ac.getBean(DiscountPolicy.class));
}
이러한 중복 빈 오류에 대해, 빈 이름을 통해 Bean을 조회하므로써 오류를 피할 수 있다.
@Test
@DisplayName("부모 타입으로 조회시 자식이 둘 이상 있으면 빈이름을 지정한다.")
void findBeanByParentTypeBeanName(){
DiscountPolicy fixDiscountPolicy = ac.getBean("fixDiscountPolicy", DiscountPolicy.class);
assertThat(fixDiscountPolicy).isInstanceOf(FixDiscountPolicy.class);
}
아래는 빈 이름이 아닌 구현 클래스를 통해 Bean을 조회하는 코드이다.
@Test
@DisplayName("특정 회원타입으로 조회")
void findBeanBySubType(){
DiscountPolicy fixDiscountPolicy = ac.getBean(FixDiscountPolicy.class);
assertThat(fixDiscountPolicy).isInstanceOf(FixDiscountPolicy.class);
}
하지만 이런 코드는 구현객체에 직접적으로 의존하게 되므로 이런 방식은 지양해야한다.
이러한 Bean 의 성질 때문에 자바의 모든 객체의 부모인 Object를 통해 Bean을 조회하면, 아래와 같이 컨테이너에 등록된 모든 Bean 을 조회할 수 있다.
@Test
@DisplayName("부모타입으로 모두 조회")
void findAllBeanByObjectType(){
Map<String, Object> beansOfType = ac.getBeansOfType(Object.class);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value = " + beansOfType.get(key));
}
}
프로그래머스 코딩테스트 연습문제 - 실패율
오늘 푼 문제는 실패율 이었다.
import java.util.*;
class Solution {
public int[] solution(int N, int[] stages) {
Map<Integer,Double> stageFailRates = new HashMap<>();
int allUser = stages.length;
int stageUser;
double failRate;
for (int stage = 1; stage <= N; stage++) {
stageUser = getUserNumber(stages,stage);
failRate = (double)stageUser / allUser;
stageFailRates.put(stage, failRate);
allUser -= stageUser;
allUser = allUser == 0 ? 1 : allUser;
}
List<Integer> keySetList = new ArrayList<>(stageFailRates.keySet());
keySetList.sort((o1, o2) -> stageFailRates.get(o2).compareTo(stageFailRates.get(o1)));
int[] answer = new int[N];
for (int i = 0; i < answer.length; i++) {
answer[i] = keySetList.get(i);
}
return answer;
}
private int getUserNumber(int[] stages,int findStage){
int number = 0;
for (int stage : stages) {
if(stage == findStage){
number++;
}
}
return number;
}
}
이제 문제를 풀면서 코드의 길이에 크게 집중하기보단 왜 이렇게 코드를 짜는지에 대해 생각하면서 풀어보려고 했다.
문제자체가 어렵지는 않았지만, 아직 자바의 스트림, 람다 등의 사용이 익숙하지 않은 상태에서 이를 에디터의 도움을 받아 사용하는 것이 찝찝한 한편, 조금 더 시간이 걸리더라도 라이브러리 사용을 자제하고 순수한 내 코드로 문제를 푸는 것과, 자바가 제공하는 라이브러리들을 적극 활용하여 푸는 것 사이에서 고민이 많았다. 결국 이를 판단하기 위해선 라이브러리의 동작을 정확히 이해해야만 그 때 그때 필요한 것을 알맞게 사용할 수 있겠다는 결론에 도달했다. 이번 주가 가기전에 Stream 이 어떻게 동작하고 어떨 때 사용해야하는지 정리해보고 많이 사용해봐야겠다.
결론 및 느낀 점
공부를 하면 할수록 더많은 공부할 것 들이 생기면서, 여기 저기 해매는 시간 때문에 처음 시작했을 때보다 공부가 수월하게 진행 되지 않는 느낌이다. 그래도 매일 블로그에 공부내용을 기록하는 것이, 공부할 수있는 큰 원동력이 되는 것 같다. 앞으로 일주일 뒤에는, 한달뒤에는 그리고 1년 뒤에는 더 퀄리티 있는 글을 쓸 수 있도록 더 고민하고 노력하는 사람이 되어야겠다.
'TIL' 카테고리의 다른 글
[2022-1-13]스프링 핵심 원리 - 기본편 : 컴포넌트 스캔 (0) | 2022.01.14 |
---|---|
[2022-1-12] 스프링 핵심원리 - 기본편 : 싱글톤 컨테이너 (0) | 2022.01.12 |
[2022-1-9]프로그래머스 레벨1 10문제 (0) | 2022.01.10 |
[2022-1-8] 스프링 핵심 원리 - 기본편 : 스프링 컨테이너와 스프링 빈 (1/2) / 프로그래머스 연습문제 - 폰켓몬(Set, HashSet) (0) | 2022.01.09 |
[2022-1-7] 프로그래머스 연습 문제 - 소수 만들기(조합, DFS 응용) (0) | 2022.01.08 |