• [Spring] ๊น€์˜ํ•œ ์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ <์„น์…˜3. ์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ ์ดํ•ด2 - ๊ฐ์ฒด ์ง€ํ–ฅ ์›๋ฆฌ ์ ์šฉ> ์ •๋ฆฌ

    2023. 10. 11.

    by. @leeeun

    ์„น์…˜3. ์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ ์ดํ•ด2 - ๊ฐ์ฒด ์ง€ํ–ฅ ์›๋ฆฌ ์ ์šฉ

     

    ์ƒˆ๋กœ์šด ํ• ์ธ ์ •์ฑ… ๊ฐœ๋ฐœ

    ์ƒˆ๋กœ์šด ํ• ์ธ ์ •์ฑ…์„ ํ™•์žฅํ•ด๋ณด์ž.

    • ์•…๋• ๊ธฐํš์ž: ์„œ๋น„์Šค ์˜คํ”ˆ ์ง์ „์— ํ• ์ธ ์ •์ฑ…์„ ์ง€๊ธˆ์ฒ˜๋Ÿผ ๊ณ ์ • ๊ธˆ์•ก ํ• ์ธ์ด ์•„๋‹ˆ๋ผ ์ข€ ๋” ํ•ฉ๋ฆฌ์ ์ธ ์ฃผ๋ฌธ ๊ธˆ์•ก๋‹น ํ• ์ธํ•˜๋Š” ์ •๋ฅ % ํ• ์ธ์œผ๋กœ ๋ณ€๊ฒฝ

    ⇒ ์ด์™€ ๊ฐ™์€ ์ƒํ™ฉ์— ๋Œ€์‘ํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ์ฒด์ง€ํ–ฅ ์„ค๊ณ„ ์›์น™์„ ์ค€์ˆ˜

    • Agile software
      • ๊ฐœ์ธ๊ณผ ๊ฐœ์ธ ๊ฐ„์˜ ์ƒํ˜ธ์ž‘์šฉ์ด ํ”„๋กœ์„ธ์Šค ๋ฐ ํˆด๋ณด๋‹ค ์šฐ์„ 
      • ์ž‘๋™ํ•˜๋Š” ์†Œํ”„ํŠธ์›จ์–ด๊ฐ€ ํฌ๊ด„์ ์ธ ๋ฌธ์„œ๋ณด๋‹ค ์šฐ์„ 
      • ๊ณ ๊ฐ๊ณผ์˜ ํ˜‘์—…์ด ๊ณ„์•ฝ ํ˜‘์ƒ๋ณด๋‹ค ์šฐ์„ 
      • ๋ณ€ํ™”์— ๋Œ€์‘ํ•˜๋Š” ๊ฒƒ์ด ๊ณ„ํš์„ ๋”ฐ๋ฅด๋Š” ๊ฒƒ๋ณด๋‹ค ์šฐ์„ 
    • ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ ๋ฐฉ์‹. 4๊ฐ€์ง€ ์›์น™

    RateDiscountPolicy ์ถ”๊ฐ€

    package hello.core.discount;
    
    import hello.core.member.Grade;
    import hello.core.member.Member;
    
    public class FixDiscountPolicy implements DiscountPolicy{
    
        private int discountFixAmount=1000;//1000์› ํ• ์ธ
        @Override
        public int discount(Member member, int price) {
            if (member.getGrade() == Grade.VIP){ //VIP๋ฉด 1000์› ํ• ์ธ
                return discountFixAmount;
            } else{
                return 0; //VIP ์•„๋‹ˆ๋ฉด ํ• ์ธ ์—†์Œ
            }
        }
    }
    

    ํ…Œ์ŠคํŠธ ์ž‘์„ฑ

    import org.assertj.core.api.Assertions;
    import org.junit.jupiter.api.DisplayName;
    import org.junit.jupiter.api.Test;
    
    import static org.assertj.core.api.Assertions.*;
    import static org.junit.jupiter.api.Assertions.*;
    
    class RateDiscountPolicyTest {
        RateDiscountPolicy discountPolicy = new RateDiscountPolicy();
    
        @Test
        @DisplayName("VIP๋Š” 10% ํ• ์ธ์ด ์ ์šฉ๋˜์–ด์•ผ ํ•œ๋‹ค")
        void vip_o(){
            //vip๊ฐ€ ์ž˜ ์ ์šฉ๋˜๋Š”์ง€ ํ…Œ์ŠคํŠธ
    
            //given
            Member member = new Member(1L, "memberVIP", Grade.VIP);//์ž„์˜์˜ ๋ฉค๋ฒ„ ์ƒ์„ฑ
    
            //when
            int discount= discountPolicy.discount(member, 10000);
    
            //then
            assertThat(discount).isEqualTo(1000); //ํ• ์ธ๊ธˆ์•ก์ด 1000์›์ด ๋งž๋Š”์ง€ ํ™•์ธ
            //Assertions-> static importํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Œ option+enter
        }
    
        @Test
        @DisplayName("VIP๊ฐ€ ์•„๋‹ˆ๋ฉด 10% ํ• ์ธ์ด ์ ์šฉ๋˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค")//์„ฑ๊ณต์ผ€์ด์Šค๊ฐ€ ์•„๋‹Œ ์‹คํŒจ์ผ€์ด์Šค๋„ ํ…Œ์ŠคํŠธ
        void vip_x(){
            //given
            Member member = new Member(1L, "memberBASIC", Grade.BASIC);// ์ž„์˜์˜ ๋ฉค๋ฒ„ ์ƒ์„ฑ
    
            //when
            int discount= discountPolicy.discount(member, 10000);
    
            //then
            assertThat(discount).isEqualTo(0); //ํ• ์ธ์ด ๋˜์ง€ ์•Š๋Š”์ง€ ํ™•์ธ
        }
    
    }
    
    • DiscoutPolicy์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ด์šฉ → ๊ตฌํ˜„์ฒด๋กœ RateDiscountPolicy๋งŒ ์ถ”๊ฐ€๋กœ ๊ฐœ๋ฐœ

    ์ƒˆ๋กœ์šด ํ• ์ธ ์ •์ฑ… ์ ์šฉ๊ณผ ๋ฌธ์ œ์ 

    public class OrderServiceImpl implements OrderService {
     //    private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
         private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
     }
    
    • FixDiscountPolicy→ RateDiscountPolicy๋กœ ๊ฐ์ฒด๋ฅผ ์‹ค์ œ ์†Œ์Šค์ฝ”๋“œ๋กœ ๋ฐ”๊พธ์–ด์•ผ ํ•จ
    • ๊ฐ์ฒด์ง€ํ–ฅ ์„ค๊ณ„ ์›์น™์„ ์ค€์ˆ˜ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ์•„๋‹ˆ๋‹ค?
      • DIP ์œ„๋ฐ˜: ํด๋ž˜์Šค์˜ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํด๋ž˜์Šค์—๋„ ์˜์กด
      • OrderServiceImpl์ด DiscountPolicy ์ธํ„ฐํŽ˜์ด์Šค ๋ฟ๋งŒ ์•„๋‹ˆ๋ผFixDiscountPolicy์ธ ๊ตฌ์ฒด ํด๋ž˜์Šค๋„ ํ•จ๊ป˜ ์˜์กด ⇒ ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์˜์กดํ•˜๊ฒŒ ํ•˜๋„๋ก
      • OCP ์œ„๋ฐ˜: ์˜์กด์„ฑ์„ ๊ฐ€์ง€๋ฏ€๋กœ FixDiscountPolicy๋ฅผ RateDiscountPolicy๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ์ˆœ๊ฐ„ OrderServiceImpl ์˜ ์†Œ์Šค ์ฝ”๋“œ๋„ ํ•จ๊ป˜ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค ⇒ ๊ตฌํ˜„์ฒด๋ฅผ ๋ฐ”๊ฟ”๋„ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ ์•ˆ ๊ณ ์น˜๋„๋ก

    ์ฝ”๋“œ ๋ณ€๊ฒฝ

    public class OrderServiceImpl implements OrderService {
         //private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
         private DiscountPolicy discountPolicy;
    }
    
    • NPE ๋ฐœ์ƒ : ํ…Œ์ŠคํŠธ๊ฐ€ createOrder()๋ฅผ ํ˜ธ์ถœ → discountPolicy์— ์•„๋ฌด ๊ฐ’๋„ ํ• ๋‹น์ด ์•ˆ ๋˜์–ด ์žˆ์Œ(๊ตฌ์ฒดํ™”๋œ ๊ฐ์ฒด๊ฐ€ ์—†์Œ)

    ํ•ด๊ฒฐ๋ฐฉ์•ˆ

    • ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ํด๋ผ์ด์–ธํŠธ์ธ OrderServiceImpl ์— DiscountPolicy ์˜ ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ๋Œ€์‹  ์ƒ์„ฑํ•˜๊ณ  ์ฃผ์ž…
    • static import

    ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ

    ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ „๋ฐ˜์ ์ธ ์šด์˜์—์„œ ์ค‘์š”ํ•˜๋‹ค!

    • ์ด์ „์˜ ์ฝ”๋“œ๋Š” OrderServiceImpl(๊ตฌํ˜„์ฒด)์ด discountPolicy(๊ตฌํ˜„์ฒด)๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์„ ํƒํ•˜๋Š” ๋ฐฉ์‹ (๋งˆ์น˜ ๋ฐฐ์šฐ๊ฐ€ ๋ฐฐ์šฐ๋ฅผ ์„ ํƒํ•˜๋“ฏ)
    • ๋ฐฐ์šฐ๋ฅผ ์ง€์ •ํ•˜๋Š” ๊ณต์—ฐ ๊ธฐํš์ž์˜ ์—ญํ• ์„ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด ๋ฐฐ์šฐ์™€ ๊ณต์—ฐ ๊ธฐํš์ž์˜ ์ฑ…์ž„์„ ๋ถ„๋ฆฌํ•˜์ž⇒ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์—ญํ• (๊ตฌํ˜„์ฒด)์„ ์ง€์ •ํ•˜๋Š” ๋ณ„๋„์˜ ๊ด€๋ฆฌ์ž๋ฅผ ๋‘์ž! (AppConfig)

    AppConfig

    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ „์ฒด ๋™์ž‘ ๋ฐฉ์‹์„ ๊ตฌ์„ฑ(config)ํ•˜๊ธฐ ์œ„ํ•ด, ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์—ฐ๊ฒฐํ•˜๋Š” ์ฑ…์ž„์„ ๊ฐ€์ง€๋Š” ๋ณ„๋„์˜ ์„ค์ • ํด๋ž˜์Šค
    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „๋ฐ˜์— ๋Œ€ํ•œ ์šด์˜์„ ๋‹ด๋‹น
    • ์ด์ „์—๋Š” memberservice ์•ˆ์—์„œ ์ธํ„ฐํŽ˜์ด์Šค, ๊ฐ์ฒด์˜ ํ• ๋‹น์„ ์ง์ ‘ํ•จ ex) MemoryMemberRepository์˜ ์ง€์ •์„ MemberServiceImpl์ด ํ•จ ๋งˆ์น˜ ๋ฐฐ์šฐ๊ฐ€ ๋ฐฐ์šฐ๋ฅผ ์„ญ์™ธํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ..

    AppConfig

    package hello.core;
     import hello.core.discount.FixDiscountPolicy;
     import hello.core.member.MemberService;
     import hello.core.member.MemberServiceImpl;
     import hello.core.member.MemoryMemberRepository;
     import hello.core.order.OrderService;
     import hello.core.order.OrderServiceImpl;
     public class AppConfig {
         public MemberService memberService() {
             return new MemberServiceImpl(new MemoryMemberRepository()); //impl์€ repository๋ฅผ ์“ธ ๊ฑฐ๋ผ๊ณ  ์ฃผ์ž…!
    }
         public OrderService orderService() {
             return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
    }
    
    • AppConfig๋กœ ๋ฉค๋ฒ„์„œ๋น„์Šค ํ˜ธ์ถœ → ๋ฉค๋ฒ„์„œ๋น„์Šค ๊ตฌํ˜„์ฒด ์ƒ์„ฑ ์ด๋•Œ ๋ฉ”๋ชจ๋ฆฌ๋ฉค๋ฒ„๋ฆฌํŒŒ์ง€ํ† ๋ฆฌ๊ฐ€ ์ƒ์„ฑ
    • MemberServiceImpl์— MemoryMemberRepository ์ฝ”๋“œ๊ฐ€ ์—†๊ณ  MemberRepository์˜ ์ฝ”๋“œ๋งŒ ์žˆ์Œ(์ถ”์ƒํ™”์—๋งŒ ์˜์กด→ DIP ์›์น™ ์ค€์ˆ˜) ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด์„œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ⇒ ์ƒ์„ฑ์ž ์ฃผ์ž…
    • OrderService์˜ ์ฝ”๋“œ๋„ ์ˆ˜์ • ๊ตฌ์ฒด์ ์ธ ํด๋ž˜์Šค๊ฐ€ ์•„๋‹Œ ์ธํ„ฐํŽ˜์ด์Šค์—๋งŒ ์˜์กดํ•˜๋„๋ก
    • AppConfig๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์‹ค์ œ ๋™์ž‘์— ํ•„์š”ํ•œ ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ MemberServiceImpl
    • MemoryMemberRepository OrderServiceImpl FixDiscountPolicy

    ์ด์ „์—๋Š” ๊ตฌํ˜„์ฒด ์•ˆ์—์„œ newํ•˜๊ณ  ๊ฐ์ฒด ์ƒ์„ฑํ•˜๋˜๊ฒŒ ์‚ฌ๋ผ์ง. AppConfig๋กœ ์—ญํ• ์ด ๋„˜์–ด๊ฐ

    • AppConfig๋Š” ์ƒ์„ฑํ•œ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค์˜ ์ฐธ์กฐ(๋ ˆํผ๋Ÿฐ์Šค)๋ฅผ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด์„œ ์ฃผ์ž…(์—ฐ๊ฒฐ)
      • MemberServiceImpl→ MemoryMemberRepository
      • OrderServiceImpl→MemoryMemberRepository, FixDiscountPolicy

    ex) MemberServiceImpl์ด new๋กœ MemoryMemberRepository๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ์ด์— ๋Œ€ํ•œ ์ฐธ์กฐ๊ฐ’์„ ๋„ฃ์–ด์คŒ

    MemberServiceImpl

    package hello.core.member;
    
    //๋ฉค๋ฒ„ ์„œ๋น„์Šค implement์˜ ๊ตฌํ˜„์ฒด -> ํšŒ์› ๊ฐ€์ž…๊ณผ ์กฐํšŒ๋ฅผ ์œ„ํ•ด์„œ ์–ด๋–ค ๊ฒƒ์ด ํ•„์š”ํ• ๊นŒ? => ๋ฉค๋ฒ„ ๋ ˆํŒŒ์ง€ํ† ๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํ•„์š”
    public class MemberServiceImpl implements MemberService {
    
        //์˜ค๋ฅธ์ชฝ ๋ถ€๋ถ„ -> ์‹ค์ œ ํ• ๋‹นํ•˜๋Š” ๋ถ€๋ถ„์ด ๊ตฌํ˜„์ฒด๋ฅผ ์˜์กด (์ถ”์ƒํ™”, ๊ตฌ์ฒดํ™” ๋‘˜ ๋‹ค์— ์˜์กด) => DIP ์œ„๋ฐ˜
        private final MemberRepository memberRepository;  //= new MemoryMemberRepository(); ์ฝ”๋“œ์ˆ˜์ •
        //๋‹จ์ˆœํžˆ ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์ ์œผ๋ฉด null point exception ๋ฐœ์ƒ -> ๊ตฌํ˜„ ๊ฐ์ฒด ์„ ํƒ(MemoryMemberRepository)
    
        public MemberServiceImpl(MemberRepository memberRepository) { //์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ๋ฉค๋ฒ„ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ์–ด๋–ค ๊ตฌํ˜„์ฒด๊ฐ€ ๋“ค์–ด๊ฐˆ์ง€ ๊ฒฐ์ •
            this.memberRepository = memberRepository;
        }
    
        @Override
        public void join(Member member) {
            memberRepository.save(member); //๋‹คํ˜•์„ฑ์— ์˜ํ•ด memberRepository์˜ save๊ฐ€ ํ˜ธ์ถœ๋จ
        }
    
        @Override
        public Member findMember(Long memberId) {
            return memberRepository.findById(memberId);
        }
    }
    
    • ์„ค๊ณ„ ๋ณ€๊ฒฝ์œผ๋กœ MemberServiceImpl ์€ MemoryMemberRepository ๋ฅผ ์˜์กดํ•˜์ง€ ์•Š๋Š”๋‹ค!
    • ๋‹จ์ง€ MemberRepository ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์˜์กดํ•œ๋‹ค.
    • MemberServiceImpl ์ž…์žฅ์—์„œ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์–ด๋–ค ๊ตฌํ˜„ ๊ฐ์ฒด๊ฐ€ ๋“ค์–ด์˜ฌ์ง€(์ฃผ์ž…๋ ์ง€)๋Š” ์•Œ ์ˆ˜ ์—†๋‹ค.
    • MemberServiceImpl ์˜ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด์„œ ์–ด๋–ค ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…ํ• ์ง€๋Š” ์˜ค์ง ์™ธ๋ถ€( AppConfig )์—์„œ ๊ฒฐ์ •๋œ๋‹ค.
    • MemberServiceImpl ์€ ์ด์ œ๋ถ€ํ„ฐ ์˜์กด๊ด€๊ณ„์— ๋Œ€ํ•œ ๊ณ ๋ฏผ์€ ์™ธ๋ถ€์— ๋งก๊ธฐ๊ณ  ์‹คํ–‰์—๋งŒ ์ง‘์ค‘ํ•˜๋ฉด ๋œ๋‹ค.

    ๊ทธ๋ฆผ - ํด๋ž˜์Šค ๋‹ค์ด์–ด๊ทธ๋žจ

    • MemberService ์ธํ„ฐํŽ˜์ด์Šค
    • ์ด๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด MemberServiceimpl์ด๊ณ , ์ด๋Š” MemberRepository ์ธํ„ฐํŽ˜์ด์Šค ์˜์กด
    • AppConfig์˜ ์ƒˆ๋กœ์šด ๋“ฑ์žฅ → MemberServiceImpl๊ณผ MemmoryMemberRepository๊นŒ์ง€ ์ƒ์„ฑ ⇒ ๊ฐ์ฒด์˜ ์ƒ์„ฑ๊ณผ ์—ฐ๊ฒฐ์€ AppConfig๊ฐ€ ๋‹ด๋‹น!
    • ๊ฐ์ฒด์˜ ์ƒ์„ฑ๊ณผ ์—ฐ๊ฒฐ(Config) ์‹คํ–‰ํ•˜๋Š” ์—ญํ• (MemberServiceImpl)

     

    ๊ทธ๋ฆผ - ํšŒ์› ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค ๋‹ค์ด์–ด๊ทธ๋žจ

    • AppConfig๊ฐ€ MemoryMemberRepository ์ƒ์„ฑ → memberServiceImpl์„ ์ƒ์„ฑํ•  ๋•Œ MemoryMemberRepository์˜ ์ฐธ์กฐ๊ฐ’์„ ์ƒ์„ฑ์ž์— ๊ฐ™์ด ์ „๋‹ฌ
    • ํด๋ผ์ด์–ธํŠธ์ธ memberServiceImpl ์ž…์žฅ์—์„œ ๋ณด๋ฉด ์˜์กด๊ด€๊ณ„๋ฅผ ๋งˆ์น˜ ์™ธ๋ถ€์—์„œ ์ฃผ์ž…ํ•ด์ฃผ๋Š” ๊ฒƒ ๊ฐ™๋‹ค๊ณ  ํ•ด์„œ DI(Dependency Injection) ์šฐ๋ฆฌ๋ง๋กœ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… ๋˜๋Š” ์˜์กด์„ฑ ์ฃผ์ž…์ด๋ผ ํ•œ๋‹ค.

     

    OrderServiceImpl

    package hello.core.order;
    
    import hello.core.discount.DiscountPolicy;
    import hello.core.discount.FixDiscountPolicy;
    import hello.core.member.Member;
    import hello.core.member.MemberRepository;
    import hello.core.member.MemoryMemberRepository;
    
    //๋‹จ์ผ ์ฑ…์ž„ ์›์น™์„ ์ž˜ ์ง€ํ‚จ ๋ฐฉ์‹ ํ• ์ธ์— ๋Œ€ํ•œ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•˜๋ฉด ์ฃผ๋ฌธ์ชฝ ์ฝ”๋“œ๋ฅผ ๊ณ ์น  ํ•„์š”๊ฐ€x
    public class OrderServiceImpl implements OrderService {
    
        private final MemberRepository memberRepository; // = new MemoryMemberRepository();
        private final DiscountPolicy discountPolicy; // = new FixDiscountPolicy();
    
        public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
            this.memberRepository = memberRepository;
            this.discountPolicy = discountPolicy;
        }
    
        @Override
        public Order createOrder(Long memberId, String itemName, int itemPrice) {
            Member member=memberRepository.findById(memberId); //ํšŒ์›์ •๋ณด ์กฐํšŒ
            int discountPrice=discountPolicy.discount(member, itemPrice); //ํ• ์ธ์ •์ฑ…์— ํšŒ์› ์ •๋ณด๋ฅผ ๋„˜๊น€ ๊ทธ๋ฆฌ๊ณ  ์ตœ์ข…์ ์œผ๋กœ ํ• ์ธ๋œ ๊ฐ€๊ฒฉ์„ ๋ฐ˜ํ™˜
    
            return new Order(memberId, itemName, itemPrice, discountPrice); //์ตœ์ข… ์ƒ์„ฑ๋œ ์ฃผ๋ฌธ ์ •๋ณด๋ฅผ ๋„˜๊ธด๋‹ค
        }
    }
    

    ์„ค๊ณ„ ๋ณ€๊ฒฝ์œผ๋กœ OrderServiceImpl ์€ FixDiscountPolicy ๋ฅผ ์˜์กดํ•˜์ง€ ์•Š๋Š”๋‹ค! ๋‹จ์ง€ DiscountPolicy ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์˜์กดํ•œ๋‹ค.

    OrderServiceImpl ์ž…์žฅ์—์„œ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์–ด๋–ค ๊ตฌํ˜„ ๊ฐ์ฒด๊ฐ€ ๋“ค์–ด์˜ฌ์ง€(์ฃผ์ž…๋ ์ง€)๋Š” ์•Œ ์ˆ˜ ์—†๋‹ค.

    OrderServiceImpl ์˜ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด์„œ ์–ด๋–ค ๊ตฌํ˜„ ๊ฐ์ฒด์„ ์ฃผ์ž…ํ• ์ง€๋Š” ์˜ค์ง ์™ธ๋ถ€( AppConfig )์—์„œ ๊ฒฐ์ •ํ•œ๋‹ค. OrderServiceImpl ์€ ์ด์ œ๋ถ€ํ„ฐ ์‹คํ–‰์—๋งŒ ์ง‘์ค‘ํ•˜๋ฉด ๋œ๋‹ค.

    OrderServiceImpl ์—๋Š” MemoryMemberRepository , `FixDiscountPolicy' ๊ฐ์ฒด์˜ ์˜์กด๊ด€๊ณ„๊ฐ€ ์ฃผ์ž…๋œ๋‹ค.

    AppConfig ์‹คํ–‰

    MemberApp

    package hello.core;
    
    import hello.core.member.Grade;
    import hello.core.member.Member;
    import hello.core.member.MemberService;
    import hello.core.member.MemberServiceImpl;
    import hello.core.order.AppConfig;
    
    public class MemberApp {
        public static void main(String[] args) {
            AppConfig appConfig = new AppConfig();
            MemberService memberService = appConfig.memberService(); //memberService ์ธํ„ฐํŽ˜์ด์Šค์—๋Š” memberserviceImpl์ด ๋“ค์–ด์žˆ์Œ
            //MemberService memberService = new MemberServiceImpl(); -> ๋ฉ”์ธ๋ฉ”์†Œ๋“œ์—์„œ ์ง์ ‘ ๊ตฌํ˜„์ฒด๋ฅผ ์ƒ์„ฑํ–ˆ์—ˆ๋˜ ์ด์ „ ๋ฐฉ์‹ -> ๊ตฌํ˜„์ฒด์—์„œ ๋ฆฌํŒŒ์ง€ํ† ๋ฆฌ๋ฅผ ๋˜ ์ƒ์„ฑ
            Member member = new Member(1L, "memberA", Grade.VIP); //Long type์ด๋ผ L ๋ถ™์—ฌ์ค˜์•ผ ๋จ
            memberService.join(member); //id๊ฐ€ 1, ์ด๋ฆ„์ด memberA์ธ ๋ฉค๋ฒ„์˜ ํšŒ์›๊ฐ€์ž… ์‹ค์ œ ๋™์ž‘
    
            Member findMember = memberService.findMember(1L); //๊ฐ€์ž… ๋ฉค๋ฒ„์™€ findMember๊ฐ€ ์ผ์น˜ํ•˜๋ฉด ์ œ๋Œ€๋กœ ๋™์ž‘ํ•œ ๊ฒƒ
            System.out.println("member = " + member.getName()); //์ด๋ฆ„์„ ์ถœ๋ ฅํ•ด์„œ ํ™•์ธ
            System.out.println("fineMember = " + findMember.getName());
        }
    }
    

    OrderApp

    package hello.core;
    
    import hello.core.member.Grade;
    import hello.core.member.Member;
    import hello.core.member.MemberService;
    import hello.core.member.MemberServiceImpl;
    import hello.core.order.AppConfig;
    import hello.core.order.Order;
    import hello.core.order.OrderService;
    import hello.core.order.OrderServiceImpl;
    
    public class OrderApp {
        public static void main(String[] args) {
    
            AppConfig appConfig=new AppConfig();
            MemberService memberService = appConfig.memberService();
            OrderService orderService = appConfig.orderService();
    
            //MemberService memberService = new MemberServiceImpl(null);
            //OrderService orderService = new OrderServiceImpl(null, null);
    
            Long memberId=1L;
            Member member= new Member(memberId,"memberA", Grade.VIP );
            memberService.join(member); //ํšŒ์›์„ ์ƒ์„ฑํ•ด์„œ ๊ฐ€์ž…์‹œํ‚ด -> ๋ฉ”๋ชจ๋ฆฌ ๊ฐ์ฒด์— ๋„ฃ์–ด๋†“์Œ
    
            Order order = orderService.createOrder(memberId, "itemA",10000);
            System.out.println("order = "+order);
            System.out.println("order.calculatePrice = "+ order.calculatePrice());
            //์ด๋Ÿฌํ•œ ํ”„๋ฆฐํŠธ ๋ฐฉ์‹๋ณด๋‹ค๋Š” JUnit์„ ์ด์šฉํ•˜๊ธฐ
    
        }
    }
    

    ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ˆ˜์ •

    package hello.core.member;
    
    import hello.core.order.AppConfig;
    import org.assertj.core.api.Assertions;
    import org.junit.jupiter.api.BeforeAll;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    
    public class MemberServiceTest {
    
        MemberService memberService;
    
        @BeforeEach //ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์ „ ๋ฌด์กฐ๊ฑด ์‹คํ–‰๋จ
        public void beforeEach(){
            AppConfig appConfig = new AppConfig();
            memberService= appConfig.memberService();
        }
    
        @Test
        void join() {
    
            //given => ์ด๊ฒŒ ์ฃผ์–ด์ง€๋ฉด
            Member member= new Member(1L, "memberA", Grade.VIP);
    
            //when => ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด
            memberService.join(member);
            Member findMember=memberService.findMember(1L);
    
            //then => ๊ฒฐ๊ณผ๊ฐ€ ์š”๋ ‡๋‹ค~ ๊ฒ€์ฆํ•ด๋ณธ๋‹ค
            Assertions.assertThat(member).isEqualTo(findMember);
    
        }
    }
    

    ์ •๋ฆฌ

    • AppConfig๋ฅผ ํ†ตํ•ด์„œ ๊ด€์‹ฌ์‚ฌ๋ฅผ ํ™•์‹คํ•˜๊ฒŒ ๋ถ„๋ฆฌ →AppConfig๋Š” ๊ตฌ์ฒด ํด๋ž˜์Šค๋ฅผ ์„ ํƒ/ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•ด์•ผ ํ• ์ง€ ์ „์ฒด ๊ตฌ์„ฑ์„ ์ฑ…์ž„
    • ๊ตฌํ˜„์ฒด๋“ค์€ ๋‹ด๋‹น ๊ธฐ๋Šฅ์„ ์‹คํ–‰ํ•˜๋Š” ์ฑ…์ž„๋งŒ → OrderServiceImpl ์€ ๊ธฐ๋Šฅ์„ ์‹คํ–‰ํ•˜๋Š” ์ฑ…์ž„๋งŒ ์ง€๋ฉด ๋œ๋‹ค.

    AppConfig ๋ฆฌํŒฉํ„ฐ๋ง

    ํ˜„์žฌ AppConfig๋ฅผ ๋ณด๋ฉด ์ค‘๋ณต์ด ์žˆ๊ณ , ์—ญํ• ์— ๋”ฐ๋ฅธ ๊ตฌํ˜„์ด ์ž˜ ์•ˆ๋ณด์ธ๋‹ค.

    • ์ค‘๋ณต์„ ์ œ๊ฑฐํ•˜๊ณ , ์—ญํ• ์— ๋”ฐ๋ฅธ ๊ตฌํ˜„์ด ๋ณด์ด๋„๋ก ๋ฆฌํŒฉํ„ฐ๋ง
    • ๋ฐ‘์— ์ฝ”๋“œ๊ฐ€ ์™œ ๋” ์—ญํ• ์— ๋”ฐ๋ฅธ ๊ตฌํ˜„์ด ์ž˜ ๋ณด์ด๋Š”๊ฑด์ง€… ๋ชจ๋ฅด๊ฒ ๋„ค..

    ์ƒˆ๋กœ์šด ๊ตฌ์กฐ์™€ ํ• ์ธ ์ •์ฑ… ์ ์šฉ

    • ์ด์ „์—๋Š” ํ• ์ธ ์ •์ฑ…์„ ๋ณ€๊ฒฝํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๊นŒ์ง€ ๋ณ€๊ฒฝ → ์ง€๊ธˆ์€ ํ• ์ธ ์ •์ฑ…์„ ๋ณ€๊ฒฝํ•ด๋„ AppConfig๋งŒ ๋ณ€๊ฒฝํ•˜๋ฉด ๋จ
    • ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ/๊ตฌ์„ฑํ•˜๋Š” ์˜์—ญ๊ณผ ์‚ฌ์šฉ ์˜์—ญ์„ ๋ถ„๋ฆฌ
    • ํ• ์ธ ์ •์ฑ… ๋ณ€๊ฒฝ ์‹œ AppConfig ๊ตฌ์„ฑ ์˜์—ญ์˜ ์ฝ”๋“œ๋งŒ ๋ณ€๊ฒฝํ•˜๋ฉด ๋จ

    ํ• ์ธ ์ •์ฑ… ๋ณ€๊ฒฝ

    public class AppConfig{
    	public DiscountPolicy discountPolicy(){
    		//return new FixDiscountPolicy();
    		return new RateDiscountPolicy();
    	}
    }
    
    • ํ• ์ธ ์ •์ฑ…์— ๋Œ€ํ•œ ๊ตฌ์ฒด ๊ฐ์ฒด๋ฅผ RateDiscountPolicy()๋กœ๋งŒ ๋ฐ”๊พผ๋‹ค

    ๋‚˜๋Š” RateDiscountPolicy()๋กœ ๋ฐ”๊ฟ”๋„ ์™œ 1000์› ๊ณ ์ •์ ์œผ๋กœ ํ• ์ธ๋˜์ง€..?

    ํ• ์ธ ์ •์ฑ… ๋ณ€๊ฒฝ

    ์ด ๊ทธ๋ฆผ ๊ต‰์žฅํžˆ ์ค‘์š”ํ•˜๋‹ค

    ์‚ฌ์šฉ์˜์—ญ์— ์žˆ๋Š” ์ฝ”๋“œ๋Š” ์† ๋Œˆ ํ•„์š”๊ฐ€ ์—†๋‹ค

    • ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ(OrderServiceImpl)๋Š” ์ถ”์ƒํ™”์— ์˜์กด (DIP๋ฅผ ๋งŒ์กฑ)
    • OCP ํ™•์žฅ์—๋Š” ์—ด๋ ค์žˆ๊ณ  ๋ณ€๊ฒฝ์—๋Š” ๋‹ซํ˜€์žˆ๋‹ค

    ์ง€๊ธˆ๊นŒ์ง€์˜ ์ „์ฒด ํ๋ฆ„ ์ •๋ฆฌ

    ์ƒˆ๋กœ์šด ํ• ์ธ ์ •์ฑ… ๊ฐœ๋ฐœ

    ๋‹คํ˜•์„ฑ ๋•๋ถ„์— ์ƒˆ๋กœ์šด ์ •๋ฅ  ํ• ์ธ ์ •์ฑ… ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€๋กœ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒƒ ์ž์ฒด๋Š” ์•„๋ฌด ๋ฌธ์ œ๊ฐ€ ์—†์Œ

    ์ƒˆ๋กœ์šด ํ• ์ธ ์ •์ฑ… ์ ์šฉ๊ณผ ๋ฌธ์ œ์ 

    • ์ƒˆ๋กœ ๊ฐœ๋ฐœํ•œ ์ •๋ฅ  ํ• ์ธ ์ •์ฑ…์„ ์ ์šฉํ•˜๋ ค๊ณ  ํ•˜๋‹ˆ *ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์ธ ์ฃผ๋ฌธ ์„œ๋น„์Šค ๊ตฌํ˜„์ฒด๋„ ํ•จ๊ป˜ ๋ณ€๊ฒฝํ•ด์•ผํ•จ ⇒ OCP์˜ ์œ„๋ฐ˜
    • ์ฃผ๋ฌธ ์„œ๋น„์Šค ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค์ธ DiscountPolicy ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ๊ตฌ์ฒด ํด๋ž˜์Šค์ธ FixDiscountPolicy ๋„ ํ•จ๊ป˜ ์˜์กด => DIP ์œ„๋ฐ˜

    ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์ธ ์ฃผ๋ฌธ ์„œ๋น„์Šค ๊ตฌํ˜„์ฒด๊ฐ€ ์ฃผ๋ฌธ๊ด€๋ จ ๊ธฐ๋Šฅ, ๊ฐ์ฒด ์ƒ์„ฑ… ๋“ฑ๋“ฑ์˜ ๋„ˆ๋ฌด ๋งŽ์€ ๊ธฐ๋Šฅ์„ ๋‹ด๋‹น ⇒ ๋ถ„๋ฆฌ

    ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ

    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ•˜๋‚˜์˜ ๊ณต์—ฐ์œผ๋กœ ์ƒ๊ฐ
    • ๊ธฐ์กด์—๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์˜์กดํ•˜๋Š” ์„œ๋ฒ„ ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•˜๊ณ , ์‹คํ–‰ํ•จ
    • ๋ฐฐ์šฐ๊ฐ€ ๋ฐฐ์šฐ๋ฅผ ์ดˆ๋น™ํ•˜๋Š”.. ๊ทธ๋Ÿฐ ์ƒํ™ฉ ⇒ ๊ณต์—ฐ ๊ตฌ์„ฑ๊ณผ ๋ฐฐ์šฐ ์„ญ์™ธํ•˜๋Š” ์ฑ…์ž„์„ ๊ฐ€์ง€๋Š” ๋ณ„๋„์˜ ๊ณต์—ฐ๊ธฐํš์ž(AppConfig)๊ฐ€ ๋“ฑ์žฅ
    • AppConfig๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ „์ฒด ๋™์ž‘ ๋ฐฉ์‹์„ ๊ตฌ์„ฑ(config)ํ•˜๊ธฐ ์œ„ํ•ด, ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์—ฐ๊ฒฐํ•˜๋Š” ์ฑ…์ž„
    • ์ด์ œ๋ถ€ํ„ฐ ํด๋ผ์ด์–ธํŠธ ๊ฐ์ฒด๋Š” ์ž์‹ ์˜ ์—ญํ• ์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ๋งŒ ์ง‘์ค‘, ๊ถŒํ•œ์ด ์ค„์–ด๋“ฌ(์ฑ…์ž„์ด ๋ช…ํ™•ํ•ด์ง)

    AppConfig ๋ฆฌํŒฉํ„ฐ๋ง

    ๊ตฌ์„ฑ ์ •๋ณด์—์„œ ์—ญํ• ๊ณผ ๊ตฌํ˜„์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ถ„๋ฆฌ ์—ญํ• ์ด ์ž˜ ๋“œ๋Ÿฌ๋‚จ ์ค‘๋ณต ์ œ๊ฑฐ (new ๋‘ ๋ฒˆ ์žˆ๋˜ ๊ฑฐ ํ•˜๋‚˜๋งŒ ํ•˜๋„๋ก)

    ์ƒˆ๋กœ์šด ๊ตฌ์กฐ์™€ ํ• ์ธ ์ •์ฑ… ์ ์šฉ

    ์ •์•ก ํ• ์ธ ์ •์ฑ… → ์ •๋ฅ % ํ• ์ธ ์ •์ฑ…์œผ๋กœ ๋ณ€๊ฒฝ AppConfig์˜ ๋“ฑ์žฅ์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ํฌ๊ฒŒ ์‚ฌ์šฉ ์˜์—ญ๊ณผ, ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ****๊ตฌ์„ฑ(Configuration)ํ•˜๋Š” ์˜์—ญ**์œผ๋กœ ๋ถ„๋ฆฌ ํ• ์ธ ์ •์ฑ…์„ ๋ณ€๊ฒฝํ•ด๋„ AppConfig๊ฐ€ ์žˆ๋Š” ๊ตฌ์„ฑ ์˜์—ญ๋งŒ ๋ณ€๊ฒฝํ•˜๋ฉด ๋จ, ์‚ฌ์šฉ ์˜์—ญ์€ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†์Œ.

    ๋ฌผ๋ก  ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์ธ ์ฃผ๋ฌธ ์„œ๋น„์Šค ์ฝ”๋“œ๋„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Œ

    ⇒ DIP, OCP์˜ ์ค€์ˆ˜

    ์ข‹์€ ๊ฐ์ฒด ์ง€ํ–ฅ ์„ค๊ณ„์˜ 5๊ฐ€์ง€ ์›์น™์˜ ์ ์šฉ

    ์—ฌ๊ธฐ์„œ๋Š” SRP, DIP, OCP ์ ์šฉ

    SRP ๋‹จ์ผ ์ฑ…์ž„ ์›์น™ : “ํ•œ ํด๋ž˜์Šค๋Š” ํ•˜๋‚˜์˜ ์ฑ…์ž„๋งŒ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค.”

    • ํด๋ผ์ด์–ธํŠธ ๊ฐ์ฒด(OrderServiceImpl๊ฐ™์€๊ฑฐ)๋Š” ์ง์ ‘ ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์—ฐ๊ฒฐํ•˜๊ณ , ์‹คํ–‰ํ•˜๋Š” ๋‹ค์–‘ํ•œ ์ฑ…์ž„์„ ๊ฐ€์ง€๊ณ  ์žˆ์Œ
    • SRP ๋‹จ์ผ ์ฑ…์ž„ ์›์น™์„ ๋”ฐ๋ฅด๋ฉด์„œ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ถ„๋ฆฌํ•จ
    • ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์—ฐ๊ฒฐํ•˜๋Š” ์ฑ…์ž„์€ AppConfig๊ฐ€ ๋‹ด๋‹น
    • ํด๋ผ์ด์–ธํŠธ ๊ฐ์ฒด๋Š” ์‹คํ–‰ํ•˜๋Š” ์ฑ…์ž„๋งŒ ๋‹ด๋‹น

    DIP ์˜์กด๊ด€๊ณ„ ์—ญ์ „ ์›์น™ : ํ”„๋กœ๊ทธ๋ž˜๋จธ๋Š” “์ถ”์ƒํ™”์— ์˜์กดํ•ด์•ผ์ง€, ๊ตฌ์ฒดํ™”์— ์˜์กดํ•˜๋ฉด ์•ˆ๋œ๋‹ค.” ์˜์กด์„ฑ ์ฃผ์ž…์€ ์ด ์›์น™์„ ๋”ฐ๋ฅด๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋‹ค.**

    • ๊ฐ์ฒด๋Š” ์ถ”์ƒํ™”์— ์˜์กด! ๊ตฌ์ฒดํ™”์— ์˜์กดํ•˜์ง€ ์•Š๋Š”๋‹ค + ์˜์กด ๊ด€๊ณ„์— ๋Œ€ํ•œ ๋ฌธ์ œ, ๊ตฌ์ฒด์ ์ธ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์„ ํƒ์€ ์™ธ๋ถ€์—์„œ ๋„ฃ์–ด์ค˜์•ผ ํ•œ๋‹ค ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๊ฐ€ DiscountPolicy ์ถ”์ƒํ™” ์ธํ„ฐํŽ˜์ด์Šค์—๋งŒ ์˜์กดํ•˜๋„๋ก ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ–ˆ๋‹ค.
    • ์ƒˆ๋กœ์šด ํ• ์ธ ์ •์ฑ…์„ ๊ฐœ๋ฐœํ•˜๊ณ , ์ ์šฉํ•˜๋ ค๊ณ  ํ•˜๋‹ˆ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋„ ํ•จ๊ป˜ ๋ณ€๊ฒฝํ•ด์•ผ ํ–ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๊ธฐ์กด ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ( OrderServiceImpl )๋Š” DIP๋ฅผ ์ง€ํ‚ค๋ฉฐ DiscountPolicy ์ถ”์ƒํ™” ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กดํ•˜๋Š” ๊ฒƒ ๊ฐ™์•˜์ง€๋งŒ, FixDiscountPolicy ๊ตฌ์ฒดํ™” ๊ตฌํ˜„ ํด๋ž˜์Šค์—๋„ ํ•จ๊ป˜ ์˜์กดํ–ˆ๋‹ค.
    • ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๊ฐ€ DiscountPolicy ์ถ”์ƒํ™” ์ธํ„ฐํŽ˜์ด์Šค์—๋งŒ ์˜์กดํ•˜๋„๋ก ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝ
    • ํ•˜์ง€๋งŒ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋งŒ์œผ๋กœ๋Š” ์•„๋ฌด๊ฒƒ๋„ ์‹คํ–‰ํ•  ์ˆ˜ ์—†๋‹ค. AppConfig๊ฐ€ FixDiscountPolicy ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ ๋Œ€์‹  ์ƒ์„ฑํ•ด์„œ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์— ์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…ํ–ˆ๋‹ค. ์ด๋ ‡๊ฒŒํ•ด์„œ DIP ์›์น™์„ ๋”ฐ๋ฅด๋ฉด์„œ ๋ฌธ์ œ๋„ ํ•ด๊ฒฐํ–ˆ๋‹ค.

    OCP : ์†Œํ”„ํŠธ์›จ์–ด ์š”์†Œ๋Š” ํ™•์žฅ์—๋Š” ์—ด๋ ค ์žˆ์œผ๋‚˜ ๋ณ€๊ฒฝ์—๋Š” ๋‹ซํ˜€ ์žˆ์–ด์•ผ ํ•œ๋‹ค

    • ๋‹คํ˜•์„ฑ ์‚ฌ์šฉํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ๊ฐ€ DIP๋ฅผ ์ง€ํ‚ด
    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‚ฌ์šฉ ์˜์—ญ๊ณผ ๊ตฌ์„ฑ ์˜์—ญ์œผ๋กœ ๋‚˜๋ˆ”
    • AppConfig๊ฐ€์˜์กด๊ด€๊ณ„๋ฅผ FixDiscountPolicy RateDiscountPolicy ๋กœ ๋ณ€๊ฒฝํ•ด์„œ ํด๋ผ์ด์–ธํŠธ์ฝ”๋“œ์— ์ฃผ์ž…ํ•˜๋ฏ€๋กœ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋Š” ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์•„๋„ ๋จ ์†Œํ”„ํŠธ์›จ์–ด ์š”์†Œ๋ฅผ ์ƒˆ๋กญ๊ฒŒ ํ™•์žฅํ•ด๋„ ์‚ฌ์šฉ ์˜์—ญ์˜ ๋ณ€๊ฒฝ์€ ๋‹ซํ˜€ ์žˆ๋‹ค!
    • ๋ณ€๊ฒฝ์ด ๋‹ซํ˜€ ์žˆ๋‹ค๋Š” ๋ง์€ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๋ง

    IoC, DI, ๊ทธ๋ฆฌ๊ณ  ์ปจํ…Œ์ด๋„ˆ

    • ๊ฐœ๋ฐœ์ž๊ฐ€ ์›ํ•˜๋Š” ๋Œ€๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ˜ธ์ถœํ•˜๋Š”, ์ง์ ‘ ๋‹ค ์ปจํŠธ๋กคํ•˜๊ณ  ์ œ์–ดํ•˜๋Š” ์Šคํƒ€์ผ์˜ ๊ฐœ๋ฐœ ↔ ๊ฐœ๋ฐœ์ž๊ฐ€ ํ˜ธ์ถœํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์ฝ”๋“œ๋ฅผ ๋Œ€์‹  ํ˜ธ์ถœ =์ œ์–ด๊ถŒ์ด ๋’ค๋ฐ”๋€๋‹ค=์ œ์–ด์˜ ์—ญ์ „

    ์ œ์–ด์˜ ์—ญ์ „ IoC(Inversion of Control)

    • ๊ธฐ์กด ํ”„๋กœ๊ทธ๋žจ์€ ํด๋ผ์ด์–ธํŠธ ๊ตฌํ˜„ ๊ฐ์ฒด๊ฐ€ ์Šค์Šค๋กœ ํ•„์š”ํ•œ ์„œ๋ฒ„ ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์—ฐ๊ฒฐํ•˜๊ณ , ์‹คํ–‰ ⇒ ํ•œ๋งˆ๋””๋กœ ๊ตฌํ˜„ ๊ฐ์ฒด๊ฐ€ ํ”„๋กœ๊ทธ๋žจ์˜ ์ œ์–ด ํ๋ฆ„์„ ์Šค์Šค๋กœ ์กฐ์ข…
    • ↔ AppConfig๊ฐ€ ๋“ฑ์žฅํ•œ ์ดํ›„์— ๊ตฌํ˜„ ๊ฐ์ฒด๋Š” ์ž์‹ ์˜ ๋กœ์ง์„ ์‹คํ–‰ํ•˜๋Š” ์—ญํ• ๋งŒ ๋‹ด๋‹นํ•œ๋‹ค. ํ”„๋กœ๊ทธ๋žจ์˜ ์ œ์–ด ํ๋ฆ„์€ ์ด์ œ AppConfig๊ฐ€ ๋‹ด๋‹น
    • ex) OrderServiceImpl ์€ ํ•„์š”ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋“ค์„ ํ˜ธ์ถœํ•˜์ง€๋งŒ ์–ด๋–ค ๊ตฌํ˜„ ๊ฐ์ฒด๋“ค์ด ์‹คํ–‰๋ ์ง€ ๋ชจ๋ฅธ๋‹ค.
    • ํ”„๋กœ๊ทธ๋žจ์— ๋Œ€ํ•œ ์ œ์–ด ํ๋ฆ„์— ๋Œ€ํ•œ ๊ถŒํ•œ์€ ๋ชจ๋‘ AppConfig๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ์‹ฌ์ง€์–ด OrderServiceImpl ๋„ AppConfig๊ฐ€ ์ƒ์„ฑ
    • AppConfig๋Š” OrderServiceImpl ์ด ์•„๋‹Œ OrderService ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋‹ค๋ฅธ ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‹คํ–‰ํ•  ์ˆ˜ ๋„ ์žˆ๋‹ค. OrderServiceImpl ์€ ๋ฌต๋ฌตํžˆ ์ž์‹ ์˜ ๋กœ์ง์„ ์‹คํ–‰

    ์ด๋ ‡๋“ฏ ํ”„๋กœ๊ทธ๋žจ์˜ ์ œ์–ด ํ๋ฆ„์„ ์ง์ ‘ ์ œ์–ดํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์™ธ๋ถ€์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ์ œ์–ด์˜ ์—ญ์ „(IoC)์ด๋ผ ํ•œ๋‹ค.

    ํ”„๋ ˆ์ž„์›Œํฌ vs ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

    • ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ์ œ์–ดํ•˜๊ณ , ๋Œ€์‹  ์‹คํ–‰ํ•˜๋ฉด ๊ทธ๊ฒƒ์€ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๋งž๋‹ค. (JUnit) → ๋ผ์ดํ”„์‚ฌ์ดํด ์†์—์„œ ๋‚ด ๊ฒƒ๋งŒ ์ฝœ๋ฐฑ์‹์œผ๋กœ ๋ถˆ๋ ค์ง€๋Š” ๊ทธ๋Ÿฐ ๋Š๋‚Œ

    ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ๊ฐœ๋ฐœํ•˜๋ฉด ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์•Œ์•„์„œ ํ˜ธ์ถœ์ด ๋˜๋Š” ๊ฒƒ

    ํ˜ธ์ถœํ•˜๋Š” ์ œ์–ด๊ถŒ์„ ๋„˜๊ธฐ๋Š” ๊ฒƒ์ด ์ œ์–ด์˜ ์—ญ์ „์ด๋‹ค!

    • ๋ฐ˜๋ฉด์— ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๊ฐ€ ์ง์ ‘ ์ œ์–ด์˜ ํ๋ฆ„์„ ๋‹ด๋‹นํ•œ๋‹ค๋ฉด ๊ทธ๊ฒƒ์€ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‹ค. (java๊ฐ์ฒด๋ฅผ xml ํ˜น์€ JSON์œผ๋กœ ๋ฐ”๊พธ๋Š” ๋“ฑ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ)

    ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… DI(Dependency Injection)

    OrderServiceImpl ์€ DiscountPolicy ์ธํ„ฐํŽ˜์ด์Šค์—๋งŒ ์˜์กด-> ์‹ค์ œ ์–ด๋–ค ๊ตฌํ˜„ ๊ฐ์ฒด๊ฐ€ ์‚ฌ์šฉ๋ ์ง€๋Š” ๋ชจ๋ฆ„ => ์˜์กด๊ด€๊ณ„๋Š” ์ •์ ์ธ ํด๋ž˜์Šค ์˜์กด ๊ด€๊ณ„์™€, ์‹คํ–‰ ์‹œ์ ์— ๊ฒฐ์ •๋˜๋Š” ๋™์ ์ธ ๊ฐ์ฒด(์ธ์Šคํ„ด์Šค) ์˜์กด ๊ด€๊ณ„ ๋‘˜์„ ๋ถ„๋ฆฌํ•ด์„œ ์ƒ๊ฐํ•ด์•ผ ํ•œ๋‹ค.

     

    ์ •์ ์ธ ํด๋ž˜์Šค ์˜์กด๊ด€๊ณ„

    • ํด๋ž˜์Šค๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” import ์ฝ”๋“œ๋งŒ ๋ณด๊ณ (ํด๋ž˜์Šค๋‚˜ ๊ฐ์ฒด๋“ค๋งŒ ๋ณด๊ณ ) ์˜์กด๊ด€๊ณ„๋ฅผ ์‰ฝ๊ฒŒ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๋‹ค. ์ •์ ์ธ ์˜์กด๊ด€๊ณ„๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜์ง€ ์•Š์•„๋„ ๋ถ„์„ํ•  ์ˆ˜ ์žˆ๋Š” ๊ด€๊ณ„
    • ํด๋ž˜์Šค ๋‹ค์ด์–ด๊ทธ๋žจ์„ ๋ณด์ž
    • ์ธํ…”๋ฆฌ์ œ์ด ํˆด ์˜ค๋ฅธ์ชฝ ๋งˆ์šฐ์Šค ํด๋ฆญ → show diagram → ์˜ค๋ฅธ์ชฝ ๋งˆ์šฐ์Šค → show dependenciesํ•˜๋ฉด ์˜์กด๊ด€๊ณ„์— ๋Œ€ํ•œ ์ฝ”๋“œ๋“ค์ด ๋ณด์ž„.

    ํด๋ž˜์Šค ๋‹ค์ด์–ด๊ทธ๋žจ์„ ํ†ตํ•ด OrderServiceImpl ์€ MemberRepository , DiscountPolicy ์— ์˜์กดํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

    ์ ์„  ํ™”์‚ดํ‘œ ๋ฐฉํ–ฅ์œผ๋กœ ์˜์กดํ•จ FixDiscountPolicy๋Š” DiscountPolicy๋ฅผ ์˜์กดํ•จ ๊ทธ๋Ÿฐ๋ฐ ์ด๋Ÿฌํ•œ ํด๋ž˜์Šค ์˜์กด๊ด€๊ณ„ ๋งŒ์œผ๋กœ๋Š” ์‹ค์ œ ์–ด๋–ค ๊ฐ์ฒด๊ฐ€ OrderServiceImpl ์— ์ฃผ์ž… ๋ ์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค. (์‹คํ–‰์‹œ์ผœ๋ด์•ผ ์•„๋Š” ๊ฒƒ!) => ๋™์ ์ธ ๊ด€๊ณ„

    ๋™์ ์ธ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค ์˜์กด ๊ด€๊ณ„

    ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ์‹œ์ ์— ์‹ค์ œ ์ƒ์„ฑ๋œ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค์˜ ์ฐธ์กฐ๊ฐ€ ์—ฐ๊ฒฐ๋œ ์˜์กด ๊ด€๊ณ„

    • ํด๋ผ์ด์–ธํŠธ๋Š” ์ฃผ๋ฌธ ์„œ๋น„์Šค ๊ตฌํ˜„์ฒด๋ฅผ ํ˜ธ์ถœ → AppConfig์—์„œ orderService ์ƒ์„ฑํ•  ๋•Œ ๊ตฌ์ฒดํ™”๋œ ๊ฐ์ฒด๊ฐ€ ๋“ค์–ด๊ฐ. ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค ๋‹ค์ด์–ด๊ทธ๋žจ์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ๋™์ ์œผ๋กœ ๋ฐ”๋€๋‹ค
    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ **์‹คํ–‰ ์‹œ์ (๋Ÿฐํƒ€์ž„)**์— ์™ธ๋ถ€์—์„œ ์‹ค์ œ ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ์— ์ „๋‹ฌํ•ด์„œ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„์˜ ์‹ค์ œ ์˜์กด๊ด€๊ณ„๊ฐ€ ์—ฐ๊ฒฐ ๋˜๋Š” ๊ฒƒ์„ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด๋ผ ํ•œ๋‹ค.
    • ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ๊ทธ ์ฐธ์กฐ๊ฐ’์„ ์ „๋‹ฌํ•ด์„œ ์—ฐ๊ฒฐ๋œ๋‹ค. (์ž๋ฐ”๋Š” ์ฐธ์กฐ๋กœ ๋‹ค ์ธ์Šคํ„ด์Šค๋“ค์ด ์—ฐ๊ฒฐ)
    • ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ , ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ˜ธ์ถœํ•˜๋Š” ๋Œ€์ƒ์˜ ํƒ€์ž… ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค. (์ •์•ก → ์ •๋ฅ  ํ• ์ธ์ •์ฑ…)
    • ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ์ •์ ์ธ ํด๋ž˜์Šค ์˜์กด๊ด€๊ณ„๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ , ๋™์ ์ธ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค ์˜์กด๊ด€๊ณ„๋ฅผ ์‰ฝ๊ฒŒ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค. ⇒ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ํด๋ž˜์Šค ๋‹ค์ด์–ด๊ทธ๋žจ์ด ๋ณ€ํ•˜์ง€ x = ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š”๋‹ค, ๊ฐ์ฒด ๋‹ค์ด์–ด๊ทธ๋žจ์€ ๋ณ€ํ™”

    IoC ์ปจํ…Œ์ด๋„ˆ, DI ์ปจํ…Œ์ด๋„ˆ

    IoC(์˜์กด๊ด€๊ณ„์˜ ์—ญ์ „์„ ์ผ์œผํ‚ด), DI(๋ฅผ ํ•ด์ฃผ๋Š” ์ปจํ…Œ์ด๋„ˆ

    AppConfig ์ฒ˜๋Ÿผ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋ฉด์„œ ์˜์กด๊ด€๊ณ„๋ฅผ ์—ฐ๊ฒฐํ•ด ์ฃผ๋Š” ๊ฒƒ์„

    IoC ์ปจํ…Œ์ด๋„ˆ ๋˜๋Š” DI ์ปจํ…Œ์ด๋„ˆ๋ผ ํ•œ๋‹ค. ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์— ์ดˆ์ ์„ ๋งž์ถ”์–ด ์ตœ๊ทผ์—๋Š” ์ฃผ๋กœ DI ์ปจํ…Œ์ด๋„ˆ๋ผ ํ•œ๋‹ค. ๋˜๋Š” ์–ด์ƒ˜๋ธ”๋Ÿฌ(๋ ˆ๊ณ  ๋ธ”๋Ÿญ์ฒ˜๋Ÿผ ์กฐ๋ฆฝ), ์˜ค๋ธŒ์ ํŠธ ํŒฉํ† ๋ฆฌ(์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ƒ์„ฑ) ๋“ฑ์œผ๋กœ ๋ถˆ๋ฆฌ๊ธฐ๋„

    ์Šคํ”„๋ง์œผ๋กœ ์ „ํ™˜ํ•˜๊ธฐ

    AppConfig ์Šคํ”„๋ง ๊ธฐ๋ฐ˜์œผ๋กœ ๋ณ€๊ฒฝ

    package hello.core;
    
    import hello.core.discount.DiscountPolicy;
    import hello.core.discount.FixDiscountPolicy;
    import hello.core.discount.RateDiscountPolicy;
    import hello.core.member.MemberService;
    import hello.core.member.MemberServiceImpl;
    import hello.core.member.MemoryMemberRepository;
    import hello.core.order.OrderService;
    import hello.core.order.OrderServiceImpl;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration //์Šคํ”„๋ง์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ตฌ์„ฑ ์ •๋ณด, ์„ค์ • ์ •๋ณด๋ผ๋Š” ๋œป
    public class AppConfig {
    
        @Bean //์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก
        public MemberService memberService(){
            return new MemberServiceImpl(memberRepository());
        }
        @Bean
        public MemoryMemberRepository memberRepository() {
            return new MemoryMemberRepository();
        }
    
        @Bean
        public OrderService orderService(){
            return new OrderServiceImpl(memberRepository(), new FixDiscountPolicy());
        }
    
        @Bean
        public DiscountPolicy discountPolicy(){
            return new RateDiscountPolicy();
        }
    }
    

    AppConfig์— ์„ค์ •์„ ๊ตฌ์„ฑํ•œ๋‹ค๋Š” ๋œป์˜ @Configuration ์„ ๋ถ™์—ฌ์ค€๋‹ค. ๊ฐ ๋ฉ”์„œ๋“œ์— @Bean ์„ ๋ถ™์—ฌ์ค€๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•œ๋‹ค.

    MemberApp์— ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ ์šฉ

    package hello.core;
    
    import hello.core.member.Grade;
    import hello.core.member.Member;
    import hello.core.member.MemberService;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class  MemberApp {
        public static void main(String[] args) {
    //        AppConfig appConfig = new AppConfig();
    //        MemberService memberService = appConfig.memberService(); //memberService ์ธํ„ฐํŽ˜์ด์Šค์—๋Š” memberserviceImpl์ด ๋“ค์–ด์žˆ์Œ
            //MemberService memberService = new MemberServiceImpl(); -> ๋ฉ”์ธ๋ฉ”์†Œ๋“œ์—์„œ ์ง์ ‘ ๊ตฌํ˜„์ฒด๋ฅผ ์ƒ์„ฑํ–ˆ์—ˆ๋˜ ์ด์ „ ๋ฐฉ์‹ -> ๊ตฌํ˜„์ฒด์—์„œ ๋ฆฌํŒŒ์ง€ํ† ๋ฆฌ๋ฅผ ๋˜ ์ƒ์„ฑ
    
            ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); //์Šคํ”„๋ง์€ ๋ชจ๋“  ๊ฒŒ Application context๋กœ ์‹œ์ž‘ -> Bean์„ ๋ชจ๋‘ ๊ด€๋ฆฌํ•ด์คŒ.
            //AppConfig์— ์žˆ๋Š” ํ™˜๊ฒฝ ์„ค์ • ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  Bean์ด ๋ถ™์€ ์• ๋“ค์„ Spring ์ปจํ…Œ์ด๋„ˆ์— ๊ฐ์ฒด ์ƒ์„ฑํ•ด์„œ ๊ด€๋ฆฌํ•ด์คŒ.
            MemberService memberService= applicationContext.getBean("memberService", MemberService.class); //Config์—์„œ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์œผ๋กœ ์ด๋ฆ„ ๋“ฑ๋ก์ด ๋จ. ๋ฉ”์„œ๋“œ ์ด๋ฆ„์ธ memberService๋กœ ๊ฐ์ฒด๋ฅผ ์ฐพ์„ ๊ฑฐ๊ณ , ๋ฐ˜ํ™˜ ํƒ€์ž…์€ MemberService์•ผ! ๋ผ๋Š”๊ฒƒ
    
            Member member = new Member(1L, "memberA", Grade.VIP); //Long type์ด๋ผ L ๋ถ™์—ฌ์ค˜์•ผ ๋จ
            memberService.join(member); //id๊ฐ€ 1, ์ด๋ฆ„์ด memberA์ธ ๋ฉค๋ฒ„์˜ ํšŒ์›๊ฐ€์ž… ์‹ค์ œ ๋™์ž‘
    
            Member findMember = memberService.findMember(1L); //๊ฐ€์ž… ๋ฉค๋ฒ„์™€ findMember๊ฐ€ ์ผ์น˜ํ•˜๋ฉด ์ œ๋Œ€๋กœ ๋™์ž‘ํ•œ ๊ฒƒ
            System.out.println("member = " + member.getName()); //์ด๋ฆ„์„ ์ถœ๋ ฅํ•ด์„œ ํ™•์ธ
            System.out.println("fineMember = " + findMember.getName());
        }
    }
    

    ์‹คํ–‰๊ฒฐ๊ณผ

    • ์œ„ ๋‹ค์„ฏ ๊ฐœ → ์Šคํ”„๋ง์ด ๋‚ด๋ถ€์ ์œผ๋กœ ํ•„์š”ํ•ด์„œ ๋“ฑ๋ก
    • ๋ฐ‘ ๋‹ค์„ฏ ๊ฐœ → ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ Key๋กœ, Value๋Š” return์— ์žˆ๋Š” ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋กœ ํ•ด์„œ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก

    OrderApp์— ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ ์šฉ

    package hello.core;
    
    import hello.core.member.Grade;
    import hello.core.member.Member;
    import hello.core.member.MemberService;
    import hello.core.order.Order;
    import hello.core.order.OrderService;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class OrderApp {
        public static void main(String[] args) {
    
    //        AppConfig appConfig=new AppConfig();
    //        MemberService memberService = appConfig.memberService();
    //        OrderService orderService = appConfig.orderService();
    
            //MemberService memberService = new MemberServiceImpl(null);
            //OrderService orderService = new OrderServiceImpl(null, null);
    
            ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
    
            MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
            OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
    
            Long memberId=1L;
            Member member= new Member(memberId,"memberA", Grade.VIP );
            memberService.join(member); //ํšŒ์›์„ ์ƒ์„ฑํ•ด์„œ ๊ฐ€์ž…์‹œํ‚ด -> ๋ฉ”๋ชจ๋ฆฌ ๊ฐ์ฒด์— ๋„ฃ์–ด๋†“์Œ
    
            Order order = orderService.createOrder(memberId, "itemA",20000);
            System.out.println("order = "+order);
            System.out.println("order.calculatePrice = "+ order.calculatePrice());
            //์ด๋Ÿฌํ•œ ํ”„๋ฆฐํŠธ ๋ฐฉ์‹๋ณด๋‹ค๋Š” JUnit์„ ์ด์šฉํ•˜๊ธฐ
    
        }
    }
    

    ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ

    • ApplicationContext ๋ฅผ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ผ ํ•œ๋‹ค.
    • ๊ธฐ์กด์—๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ AppConfig ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ง์ ‘ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  DI๋ฅผ ํ–ˆ์ง€๋งŒ, ์ด์ œ๋ถ€ํ„ฐ๋Š” ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ†ตํ•ด์„œ ์‚ฌ์šฉ
    • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” @Configuration ์ด ๋ถ™์€ AppConfig ๋ฅผ ์„ค์ •(๊ตฌ์„ฑ) ์ •๋ณด๋กœ ์‚ฌ์šฉ -> ์—ฌ๊ธฐ์„œ @Bean ์ด๋ผ ์ ํžŒ ๋ฉ”์„œ๋“œ๋ฅผ ๋ชจ๋‘ ํ˜ธ์ถœํ•ด์„œ ๋ฐ˜ํ™˜๋œ ๊ฐ์ฒด๋ฅผ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก
    • ์ด๋ ‡๊ฒŒ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋œ ๊ฐ์ฒด๋ฅผ ์Šคํ”„๋ง ๋นˆ์ด๋ผ ํ•œ๋‹ค.
    • ์Šคํ”„๋ง ๋นˆ์€ @Bean ์ด ๋ถ™์€ ๋ฉ”์„œ๋“œ์˜ ๋ช…์„ ์Šคํ”„๋ง ๋นˆ์˜ ์ด๋ฆ„์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ( memberService ,orderService ) -> @Bean(name="mm") ์ด๋Ÿฐ ์‹์œผ๋กœ ์ง€์ •๋„ ๊ฐ€๋Šฅํ•˜๊ธด ํ•จ but default๋ฅผ ๋”ฐ๋ฅด๋Š” ๊ฒŒ ๋‚˜์Œ
    • ์ด์ „์—๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ํ•„์š”ํ•œ ๊ฐ์ฒด๋ฅผ AppConfig ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ง์ ‘ ์กฐํšŒํ–ˆ์ง€๋งŒ, ์ด์ œ๋ถ€ํ„ฐ๋Š” ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ†ตํ•ด์„œ ํ•„์š”ํ•œ ์Šคํ”„๋ง ๋นˆ(๊ฐ์ฒด)๋ฅผ ์ฐพ์•„์•ผ ํ•œ๋‹ค. ์Šคํ”„๋ง ๋นˆ์€ applicationContext.getBean() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.
    • ๊ธฐ์กด์—๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ž๋ฐ”์ฝ”๋“œ๋กœ ๋ชจ๋“  ๊ฒƒ์„ ํ–ˆ๋‹ค๋ฉด ์ด์ œ๋ถ€ํ„ฐ๋Š” ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๊ฐ์ฒด๋ฅผ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๊ณ , ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—์„œ ์Šคํ”„๋ง ๋นˆ์„ ์ฐพ์•„์„œ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค.

    ์ฝ”๋“œ๊ฐ€ ์•ฝ๊ฐ„ ๋” ๋ณต์žกํ•ด์ง„ ๊ฒƒ ๊ฐ™์€๋ฐ, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋–ค ์žฅ์ ์ด ์žˆ์„๊นŒ?

    ์žฅ์ ์€ ์–ด๋งˆ์–ด๋งˆํ•˜๋‹ค!!

    ⇒ AppConfig๋ฅผ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ†ตํ•ด์„œ DI์™€ ๊ฐ™์€ ๊ฒƒ๋“ค์„ ํŽธ๋ฆฌํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ๋ฒ”์šฉ์˜ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์—ญํ• 

    ๋” ์•Œ์•„๋ณผ ๊ฒƒ

    • static import
    • ์˜์กด์„ฑ ์ฃผ์ž… DI
    • ์Šคํ”„๋ง ์–ด๋…ธํ…Œ์ด์…˜
    • ์ž๋ฐ”์˜ ๋ ˆํผ๋Ÿฐ์Šค (์ฐธ์กฐ)

    ๋‹จ์ถ•ํ‚ค

    command+shift+T : create new Test

    command+b: go to declaration or usage

    command+e: ์ด์ „ ํžˆ์Šคํ† ๋ฆฌ

    command+e+enter: ๋ฐ”๋กœ ์ด์ „์œผ๋กœ ๋Œ์•„๊ฐ

    command+o: ์ฐพ๊ธฐ

    command+option+m: extract method

    command+/: ๊ทธ ์ค„ ์ฃผ์„์ฒ˜๋ฆฌ

    command+d: ๋ผ์ธ ๋ณต์ œ

    option+ ์œ„ ํ‚ค๋ณด๋“œ: extend selection

    control: ๋งˆ์ง€๋ง‰์œผ๋กœ ์‹คํ–‰๋๋˜ ๊ฒŒ ์‹คํ–‰๋จ

    command+option+v: introduce variable

     

    ๋Œ“๊ธ€