Spring, Apache, Java

타입으로 조회한 빈 여러개가 모두 필요할 때 (List, Map)

cwchoiit 2024. 5. 27. 13:40
728x90
반응형
SMALL

이전 포스팅에 이어, 타입 하나에 여러 빈이 등록이 될 수 있는데 그 빈이 모두 필요할땐 어떻게 다뤄야 하는지를 작성하려고 한다.

예를 들면 이런 경우를 보자.

유저가 선택한 할인 정책에 따라, 고정 할인과 비율 할인을 둘 다 사용할 경우가 있을 수 있다. 그러니까 서비스 자체적으로 정책을 결정하는게 아니고 유저가 선택한 할인 정책에 따라 할인을 해주는 서비스가 있을 수 있다. 그땐 둘 다 필요하다. 이런 경우에는 List, Map을 사용할 수 있다.

 

DiscountService

static class DiscountService {
    private final Map<String, DiscountPolicy> policyMap;
    private final List<DiscountPolicy> policies;

    public DiscountService(Map<String, DiscountPolicy> policyMap,
                           List<DiscountPolicy> policies) {
        this.policyMap = policyMap;
        this.policies = policies;
        System.out.println("policyMap = " + policyMap);
        System.out.println("policies = " + policies);
    }
}

위 코드를 보자. 생성자 주입을 통해 DiscountPolicy 빈을자동 주입하려고 한다.

근데 2개 이상인 경우 이렇게 Map 또는 List로 받으면 된다. (참고로, 둘 중 하나를 사용하면 된다. 그냥 둘 다 가능하다는 것을 보여주기 위해 작성한 것 뿐이다)

 

실행 결과를 보면 다음과 같이 잘 들어간다.

실행결과

policyMap = {fixDiscountPolicy=org.example.springcore.discount.FixDiscountPolicy@5f9be66c, rateDiscountPolicy=org.example.springcore.discount.RateDiscountPolicy@3abada5a}
policies = [org.example.springcore.discount.FixDiscountPolicy@5f9be66c, org.example.springcore.discount.RateDiscountPolicy@3abada5a]

 

그래서 둘 다 필요한 경우엔 어떻게 담는지를 알아봤고, 이렇게 둘 다 가져왔을 때 그때 그때 상황에 맞게 사용하는 코드를 작성해서 테스트 해보자.

 

AllBeanTest

package org.example.springcore.autowired;

import org.assertj.core.api.Assertions;
import org.example.springcore.AutoAppConfig;
import org.example.springcore.discount.DiscountPolicy;
import org.example.springcore.member.Grade;
import org.example.springcore.member.Member;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.List;
import java.util.Map;

import static org.assertj.core.api.Assertions.*;

public class AllBeanTest {

    @Test
    void findAllBean() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);

        DiscountService discountService = ac.getBean(DiscountService.class);
        Member member = new Member(1L, "userA", Grade.VIP);
        int discountPrice = discountService.discount(member, 10000, "fixDiscountPolicy");

        assertThat(discountService).isInstanceOf(DiscountService.class);

        assertThat(discountPrice).isEqualTo(1000);

        int rateDiscountPrice = discountService.discount(member, 20000, "rateDiscountPolicy");
        assertThat(rateDiscountPrice).isEqualTo(2000);
    }

    static class DiscountService {
        private final Map<String, DiscountPolicy> policyMap;
        private final List<DiscountPolicy> policies;

        public DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) {
            this.policyMap = policyMap;
            this.policies = policies;
        }

        public int discount(Member member, int price, String discountCode) {
            DiscountPolicy discountPolicy = policyMap.get(discountCode);
            return discountPolicy.discount(member, price);
        }
    }
}

 

discount()는 세번째 파라미터로 discountCode를 받는다. 이 파라미터가 fixDiscountPolicyrateDiscountPolicy냐에 따라 할인가격을 결정하면 되는 메서드이다. 그래서 굉장히 유연하게 할인 정책을 갈아 끼울 수 있다. 이는 전략패턴과도 유사한 모습이 보인다.

 

결론

타입으로 조회한 빈이 2개 이상이고 모두 필요한 경우에 List, Map으로 받을 수 있다.

728x90
반응형
LIST