• [Spring] ๊น€์˜ํ•œ ์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ <์„น์…˜2.์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ ์ดํ•ด1 - ์˜ˆ์ œ ๋งŒ๋“ค๊ธฐ> ์ •๋ฆฌ

    2023. 10. 6.

    by. @leeeun

    ์„น์…˜2. ์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ ์ดํ•ด1 - ์˜ˆ์ œ ๋งŒ๋“ค๊ธฐ

     

    ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

    dependencies ์•„๋ฌด๊ฒƒ๋„ ์„ ํƒx

    ๋น„์ฆˆ๋‹ˆ์Šค ์š”๊ตฌ์‚ฌํ•ญ๊ณผ ์„ค๊ณ„

    • ํšŒ์›
      • ํšŒ์›์„ ๊ฐ€์ž…ํ•˜๊ณ  ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.
      • ํšŒ์›์€ ์ผ๋ฐ˜๊ณผ VIP ๋‘ ๊ฐ€์ง€ ๋“ฑ๊ธ‰์ด ์žˆ๋‹ค.
      • ํšŒ์› ๋ฐ์ดํ„ฐ๋Š” ์ž์ฒด DB๋ฅผ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๊ณ , ์™ธ๋ถ€ ์‹œ์Šคํ…œ๊ณผ ์—ฐ๋™ํ•  ์ˆ˜ ์žˆ๋‹ค. (๋ฏธํ™•์ •) ⇒ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์—ญํ• ๊ณผ ๊ตฌํ˜„์„ ๊ตฌ๋ถ„
    • ์ฃผ๋ฌธ๊ณผ ํ• ์ธ ์ •์ฑ…
      • ํšŒ์›์€ ์ƒํ’ˆ์„ ์ฃผ๋ฌธํ•  ์ˆ˜ ์žˆ๋‹ค.
      • ํšŒ์› ๋“ฑ๊ธ‰์— ๋”ฐ๋ผ ํ• ์ธ ์ •์ฑ…์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
      • ํ• ์ธ ์ •์ฑ…์€ ๋ชจ๋“  VIP๋Š” 1000์›์„ ํ• ์ธํ•ด์ฃผ๋Š” ๊ณ ์ • ๊ธˆ์•ก ํ• ์ธ์„ ์ ์šฉํ•ด๋‹ฌ๋ผ. (๋‚˜์ค‘์— ๋ณ€๊ฒฝ ๋  ์ˆ˜ ์žˆ๋‹ค.)
      • ํ• ์ธ ์ •์ฑ…์€ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค. ํšŒ์‚ฌ์˜ ๊ธฐ๋ณธ ํ• ์ธ ์ •์ฑ…์„ ์•„์ง ์ •ํ•˜์ง€ ๋ชปํ–ˆ๊ณ , ์˜คํ”ˆ ์ง์ „๊นŒ์ง€ ๊ณ ๋ฏผ์„ ๋ฏธ๋ฃจ๊ณ  ์‹ถ๋‹ค. ์ตœ์•…์˜ ๊ฒฝ์šฐ ํ• ์ธ์„ ์ ์šฉํ•˜์ง€ ์•Š์„ ์ˆ˜ ๋„ ์žˆ๋‹ค. (๋ฏธํ™•์ •) ⇒ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์—ญํ• ๊ณผ ๊ตฌํ˜„์„ ๊ตฌ๋ถ„

    ํšŒ์› ๋„๋ฉ”์ธ ์„ค๊ณ„

    ํšŒ์› ๋„๋ฉ”์ธ ํ˜‘๋ ฅ ๊ด€๊ณ„

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

    ํšŒ์› ํด๋ž˜์Šค ๋‹ค์ด์–ด๊ทธ๋žจ

    • ๋ฉค๋ฒ„ ์„œ๋น„์Šค๋ฅผ ์ธํ„ฐํŽ˜์ด์Šค๋กœ → ์ด์— ๋Œ€ํ•œ ๊ตฌํ˜„์ฒด MemberServiceImpl
    • ๋ฉค๋ฒ„ ์„œ๋น„์Šค ๋ ˆํŒŒ์ง€ํ† ๋ฆฌ(ํšŒ์› ์ €์žฅ์†Œ ์ธํ„ฐํŽ˜์ด์Šค) → ์ด์— ๋Œ€ํ•œ ๊ตฌํ˜„ ํด๋ž˜์Šค๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋ฉค๋ฒ„ ๋ ˆํŒŒ์ง€ํ† ๋ฆฌ์™€ db๋ฉค๋ฒ„ ๋ ˆํŒŒ์ง€ํ† ๋ฆฌ

    ⇒ ์‹ค์ œ ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š๊ณ  ํด๋ž˜์Šค๋“ค์„ ๋ถ„์„ํ•ด์„œ ๋ณด์—ฌ์ฃผ๋Š” ์ •์ ์ธ ๋ถ€๋ถ„

    ๊ตฌํ˜„์ฒด๋“ค์€ ๋™์ ์œผ๋กœ ๊ฒฐ์ •๋˜๋Š” ๋ถ€๋ถ„. ์„œ๋ฒ„๊ฐ€ ๋– ์•ผ ๊ฒฐ์ •๋˜๋ฏ€๋กœ ๊ฐ์ฒด ๋‹ค์ด์–ด๊ทธ๋žจ์„ ๋”ฐ๋กœ ๊ทธ๋ ค์„œ ์„œ๋ฒ„๊ฐ€ ์‹ค์ œ ๋–ด์„ ๋•Œ์˜ ๋™์ž‘์„ ๊ทธ๋ ค๋‚ธ๋‹ค

     

    ํšŒ์› ๊ฐ์ฒด ๋‹ค์ด์–ด๊ทธ๋žจ

    • ์‹ค์ œ ๊ฐ์ฒด ๊ฐ„์˜ ๋ฉ”๋ชจ๋ฆฌ ์ฐธ์กฐ๋ฅผ ๊ทธ๋ฆฐ ๊ทธ๋ฆผ
    • ํšŒ์› ์„œ๋น„์Šค๋Š” MemberServiceImpl
    • ํด๋ผ์ด์–ธํŠธ๋Š” ํšŒ์› ์„œ๋น„์Šค๋ฅผ ์ฐธ์กฐ, ํšŒ์› ์„œ๋น„์Šค๋Š” ๋ฉ”๋ชจ๋ฆฌ ํšŒ์› ์ €์žฅ์†Œ๋ฅผ ์ฐธ์กฐ

    ⇒ ์‹ค์ œ ์œ ํ•œ ์ธ์Šคํ„ด์Šค๋ผ๋ฆฌ์˜ ์ฐธ์กฐ. ๋™์ ์ธ ๋ถ€๋ถ„.

    ํ•ญ์ƒ ์ด 3๊ฐ€์ง€์˜ ๋‹ค์ด์–ด๊ทธ๋žจ์œผ๋กœ ๊ฐœ๋…์ ์ธ ๋ถ€๋ถ„์„ ํ‘œํ˜„

    ํšŒ์› ๋„๋ฉ”์ธ ๊ฐœ๋ฐœ

    ํšŒ์› ๋“ฑ๊ธ‰

    package hello.core.member;
     public enum Grade { //ํšŒ์› ๋“ฑ๊ธ‰ 2๊ฐ€์ง€
         BASIC,
    		 VIP
    }
    
    • enum : ๊ด€๋ จ์žˆ๋Š” ์ƒ์ˆ˜๋ผ๋ฆฌ ๋ชจ์•„ ์ƒ์ˆ˜๋ฅผ ๋Œ€ํ‘œํ•  ์ˆ˜ ์žˆ๋Š” ์ด๋ฆ„์œผ๋กœ ํƒ€์ž…์„ ์ •์˜, ๋งˆ์น˜ ํด๋ž˜์Šค์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ ํ•˜๋Š” ์ƒ์ˆ˜ ⇒ ๋ณ„๋„์˜ ์ž๋ฐ”๋กœ ์„ ์–ธ, class ๋‚ด๋ถ€์—์„œ ์„ ์–ธ, class ์™ธ๋ถ€์—์„œ ์„ ์–ธ

    [Java] Enum์˜ ์‚ฌ์šฉ๋ฒ•

    • enum์„ ํ†ตํ•ด BASIC๊ณผ VIP ๋‘ ๊ฐ€์ง€์˜ ํƒ€์ž…์ด ์žˆ๋Š” ํšŒ์› ๋“ฑ๊ธ‰์„ ๊ด€๋ฆฌ

     

    ํšŒ์› ์—”ํ‹ฐํ‹ฐ

    package hello.core.member;
    
    public class Member {
        private Long id;
        private String name;
        private Grade grade;
        //id,์ด๋ฆ„,grade 3๊ฐ€์ง€ ์†์„ฑ์„ ๋ณด์œ 
    
        public Member(Long id, String name, Grade grade) {
            this.id = id;
            this.name = name;
            this.grade = grade;
        }
    
        //getter-setter method๋ฅผ ํ†ตํ•ด์„œ private์˜ ๊ฐ’์„ ์„ธํŒ…
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Grade getGrade() {
            return grade;
        }
    
        public void setGrade(Grade grade) {
            this.grade = grade;
        }
    }
    
    • getter setter method : ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ๋Š” ์™ธ๋ถ€ ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜์—ฌ ๋ณ€๊ฒฝํ•˜๋„๋ก ์œ ๋„ → ์ด ์—ญํ• ์„ ํ•˜๋Š” ๊ฒƒ์ด Setter (๋ณ€์ˆ˜๋ฅผ ํ• ๋‹น)
    • ์™ธ๋ถ€์—์„œ ๊ฐ์ฒด์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ๋•Œ๋„ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉ → ์ด๋Ÿฌํ•œ ์—ญํ• ์„ ํ•˜๋Š” ๊ฒƒ์ด Getter (๋ณ€์ˆ˜๋ฅผ ๋ฐ˜ํ™˜)

     

    ํšŒ์› ์ €์žฅ์†Œ

    ํšŒ์› ์ €์žฅ์†Œ ์ธํ„ฐํŽ˜์ด์Šค

    package hello.core.member;
    
    public interface MemberRepository {
        void save(Member member); //ํšŒ์›์„ ์ €์žฅ
    
        Member findById(Long memberId); //ํšŒ์›์˜ ์•„์ด๋””๋กœ ํšŒ์›์„ ์ฐพ๋Š” ๊ธฐ๋Šฅ
    }
    
    //์ธํ„ฐํŽ˜์ด์Šค์— ๋Œ€ํ•œ ๊ตฌํ˜„์ฒด๊ฐ€ ํ•„์š”. ์ธํ„ฐํŽ˜์ด์Šค์™€ ๊ตฌํ˜„์ฒด๋ฅผ ๋‹ค๋ฅธ ํŒจํ‚ค์ง€์— ๋‘๋Š” ๊ฒƒ์ด ์ข‹์€ ์„ค๊ณ„, ์ด๋ฒˆ์—๋Š” ๊ฐ™์€ ํŒจํ‚ค์ง€๋กœ
    

    ๋ฉ”๋ชจ๋ฆฌ ํšŒ์› ์ €์žฅ์†Œ ๊ตฌํ˜„์ฒด

    package hello.core.member;
    import java.util.HashMap;
    import java.util.Map;
    
    //db๊ฐ€ ํ™•์ •๋˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฉค๋ฒ„ ๋ฆฌํŒŒ์ง€ํ† ๋ฆฌ๋ฅผ ์ด์šฉ. MemberRepository์˜ ๊ตฌํ˜„์ฒด
    public class MemoryMemberRepository implements MemberRepository{
        @Override
        public void save(Member member) {
            store.put(member.getId(), member);
        }
    
        @Override
        public Member findById(Long memberId) {
            return store.get(memberId);
        }
    
        private static Map<Long, Member> store = new HashMap<>(); //์ €์žฅ์†Œ ์—ญํ• 
        //concurrent ๋™์‹œ์„ฑ ์ด์Šˆ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์‹ค๋ฌด์—์„œ๋Š” ๋‹จ์ˆœ HashMap์ด ์•„๋‹Œ concurrent hashmap์„ ์‚ฌ์šฉํ•ด์•ผ ํ•จ.
    
    }
    

    ํšŒ์› ์„œ๋น„์Šค

    ํšŒ์› ์„œ๋น„์Šค ์ธํ„ฐํŽ˜์ด์Šค

    package hello.core.member;
    
    public interface MemberService {
        void join(Member member);
        Member findMember(Long memberId);
    }
    

    ํšŒ์› ์„œ๋น„์Šค ๊ตฌํ˜„์ฒด

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

    ํšŒ์› ๋„๋ฉ”์ธ ์‹คํ–‰๊ณผ ํ…Œ์ŠคํŠธ

    ํšŒ์› ๋„๋ฉ”์ธ - ํšŒ์› ๊ฐ€์ž… main

    package hello.core;
    
    import hello.core.member.Grade;
    import hello.core.member.Member;
    import hello.core.member.MemberService;
    import hello.core.member.MemberServiceImpl;
    
    public class MemberApp {
        public static void main(String[] args) {
            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());
        }
    }
    

    ์ง€๊ธˆ๊นŒ์ง€๋Š” Spring ๊ด€๋ จ ์ฝ”๋“œx ์ˆœ์ˆ˜ํ•œ ์ž๋ฐ”๋กœ๋งŒ ์ด๋ฃจ์–ด์ง„ ์ฝ”๋“œ๋“ค

    ์ด๋ ‡๊ฒŒ print๋ฅผ ํ†ตํ•ด ๋ฉ”์ธ ๋ฉ”์†Œ๋“œ๋ฅผ ํ…Œ์ŠคํŠธ ํ•˜๋Š” ๊ฒƒ์€ ํ•œ๊ณ„๊ฐ€ ์žˆ์Œ ⇒ JUnit test framework ์‚ฌ์šฉ (์˜ค๋ฅ˜ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ ์˜ค๋ฅ˜๋ฅผ ๋นจ๋ฆฌ catchํ•  ์ˆ˜ ์žˆ์Œ) ํ•„์ˆ˜๋กœ ์‚ฌ์šฉํ•จ.

    test์— ๋Œ€ํ•œ ์ฝ”๋“œ๋Š” ์šด์˜ํ™˜๊ฒฝ์— ๋ฐฐํฌ๋˜์ง€ ์•Š์Œ.

    ํšŒ์› ๋„๋ฉ”์ธ - ํšŒ์› ๊ฐ€์ž… ํ…Œ์ŠคํŠธ

    package hello.core.member;
    
    import org.assertj.core.api.Assertions;
    import org.junit.jupiter.api.Test;
    
    public class MemberServiceTest {
    
        MemberService memberService= new MemberServiceImpl();
        @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);
    
        }
    }
    

    ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์€ OCP,DIP๋ฅผ ์ž˜ ์ง€ํ‚ค๊ณ  ์žˆ๋Š”๊ฐ€? ์ธํ„ฐํŽ˜์ด์Šค๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๊ตฌํ˜„์ฒด๊นŒ์ง€ ๋ชจ๋‘ ์˜์กดํ•œ๋‹ค๋Š” ๋ฌธ์ œ์ ์ด ์žˆ์Œ. MemberRepository

    ์ฃผ๋ฌธ๊ณผ ํ• ์ธ ๋„๋ฉ”์ธ ์„ค๊ณ„

    ์ฃผ๋ฌธ ๋„๋ฉ”์ธ ์—ญํ• 

    1. ์ฃผ๋ฌธ ์ƒ์„ฑ: ํด๋ผ์ด์–ธํŠธ(๋ฉ”์ธ ๊ฐ™์€ ์ฝ”๋“œ ํ˜น์€ ์ปจํŠธ๋กค๋Ÿฌ) ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ฒจ์„œ ์ฃผ๋ฌธ ์„œ๋น„์Šค์— ์ฃผ๋ฌธ ์ƒ์„ฑ์„ ์š”์ฒญํ•œ๋‹ค.

    2. ํšŒ์› ์กฐํšŒ: ํ• ์ธ์„ ์œ„ํ•ด์„œ๋Š” ํšŒ์› ๋“ฑ๊ธ‰์ด ํ•„์š”ํ•˜๋‹ค. ๊ทธ๋ž˜์„œ ์ฃผ๋ฌธ ์„œ๋น„์Šค๋Š” ํšŒ์› ์ €์žฅ์†Œ์—์„œ ํšŒ์›์„ ์กฐํšŒํ•œ๋‹ค.(findbyId)

    3. ํ• ์ธ ์ ์šฉ: ์ฃผ๋ฌธ ์„œ๋น„์Šค๋Š” ํšŒ์› ๋“ฑ๊ธ‰์— ๋”ฐ๋ฅธ ํ• ์ธ ์—ฌ๋ถ€๋ฅผ ํ• ์ธ ์ •์ฑ…์— ์œ„์ž„ํ•œ๋‹ค.

    4. ์ฃผ๋ฌธ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜: ์ฃผ๋ฌธ ์„œ๋น„์Šค๋Š” ํ• ์ธ ๊ฒฐ๊ณผ๋ฅผ ํฌํ•จํ•œ ์ฃผ๋ฌธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.(์‹ค์ œ๋กœ๋Š” ์ฃผ๋ฌธ ๋ฐ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค์–ด์„œ db์— ์ €์žฅ)

     

     

    ์ฃผ๋ฌธ ๋„๋ฉ”์ธ ์ „์ฒด (์—ญํ• , ๊ตฌํ˜„)

    • ์—ญํ•  → ๊ตฌํ˜„์„ ๋ถ„๋ฆฌ. ์ž์œ ๋กญ๊ฒŒ ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์กฐ๋ฆฝ ๊ฐ€๋Šฅ. ํšŒ์› ์ €์žฅ์†Œ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํ• ์ธ ์ •์ฑ…์„ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ
    • ํด๋ผ์ด์–ธํŠธ์— ์ฃผ๋ฌธ ์„œ๋น„์Šค์— ์ฃผ๋ฌธ ์ƒ์„ฑ→ ํšŒ์› ์กฐํšŒํ•˜๊ณ  ํ• ์ธ์ •์ฑ…์„ ์กฐํšŒํ•ด์„œ ํด๋ผ์ด์–ธํŠธ์— ๋ฐ˜ํ™˜

     

    ์ฃผ๋ฌธ ๋„๋ฉ”์ธ ํด๋ž˜์Šค ๋‹ค์ด์–ด๊ทธ๋žจ

    • OrderService ์ธํ„ฐํŽ˜์ด์Šค → ์ด์— ๋Œ€ํ•œ ๊ตฌํ˜„์ฒด OrderServiceImpl

     

    ์ฃผ๋ฌธ ๋„๋ฉ”์ธ ๊ฐ์ฒด ๋‹ค์ด์–ด๊ทธ๋žจ

    ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ฃผ๋ฌธ ์„œ๋น„์Šค ๊ตฌํ˜„์ฒด๋ฅผ ํ˜ธ์ถœ → ๋ฉ”๋ชจ๋ฆฌ ํšŒ์› ์ €์žฅ์†Œ์™€ ์ •์•ก ํ• ์ธ ์ •์ฑ…์„ ํ˜ธ์ถœ

    ์—ญํ• ๋“ค์˜ ํ˜‘๋ ฅ ๊ด€๊ณ„๋ฅผ ์žฌ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ง ⇒ ๋ฉ”๋ชจ๋ฆฌ ํšŒ์› ์ €์žฅ์†Œ๊ฐ€ ๋ณ€ํ™”ํ•ด๋„, ํ• ์ธ ์ •์ฑ…์ด ๋ณ€ํ™”ํ•ด๋„ ์ฃผ๋ฌธ ์„œ๋น„์Šค ๊ตฌํ˜„์ฒด๋ฅผ ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๋ง

    ์ด๋Ÿฐ ์‹์œผ๋กœ ์ €์žฅ์†Œ์™€ ํ• ์ธ ์ •์ฑ…์ด ๋ณ€ํ™”ํ•ด๋„ ์ฃผ๋ฌธ ์„œ๋น„์Šค ์—ญํ• ์„ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค

     

    ์ฃผ๋ฌธ๊ณผ ํ• ์ธ ๋„๋ฉ”์ธ ๊ฐœ๋ฐœ

    ํ• ์ธ ์ •์ฑ… ์ธํ„ฐํŽ˜์ด์Šค

    package hello.core.discount;
    
    import hello.core.member.Member;
    
    public interface DiscountPolicy {
        //@return ํ• ์ธ๋Œ€์ƒ ๊ธˆ์•ก
        int discount(Member member, int price);
    }
    

    ์ •์•ก ํ• ์ธ ์ •์ฑ… ๊ตฌํ˜„์ฒด

    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 ์•„๋‹ˆ๋ฉด ํ• ์ธ ์—†์Œ
            }
        }
    }
    

    ์ฃผ๋ฌธ ์—”ํ‹ฐํ‹ฐ

    package hello.core.order;
    
    public class Order {
        private Long memberId;
        private String itemName;
        private int itemPrice;
        private int discountPrice;
    
        public Order(Long memberId, String itemName, int itemPrice, int discountPrice) {
            this.memberId = memberId;
            this.itemName = itemName;
            this.itemPrice = itemPrice;
            this.discountPrice = discountPrice;
        }
    
        //๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง => ํ• ์ธ ๊ธˆ์•ก์— ๋”ฐ๋ผ ๊ณ„์‚ฐ๋œ ์ตœ์ข… ๊ณ„์‚ฐ ๊ธˆ์•ก
        public int calculatePrice(){
            return itemPrice-discountPrice;
        }
        public Long getMemberId() {
            return memberId;
        }
    
        public void setMemberId(Long memberId) {
            this.memberId = memberId;
        }
    
        public String getItemName() {
            return itemName;
        }
    
        public void setItemName(String itemName) {
            this.itemName = itemName;
        }
    
        public int getItemPrice() {
            return itemPrice;
        }
    
        public void setItemPrice(int itemPrice) {
            this.itemPrice = itemPrice;
        }
    
        public int getDiscountPrice() {
            return discountPrice;
        }
    
        public void setDiscountPrice(int discountPrice) {
            this.discountPrice = discountPrice;
        }
    
        //generate toString
        @Override
        public String toString() {
            return "Order{" +
                    "memberId=" + memberId +
                    ", itemName='" + itemName + '\\'' +
                    ", itemPrice=" + itemPrice +
                    ", discountPrice=" + discountPrice +
                    '}';
        }
    }
    

    ์ฃผ๋ฌธ ์„œ๋น„์Šค ์ธํ„ฐํŽ˜์ด์Šค

    package hello.core.order;
    
    public interface OrderService {
        //์ฃผ๋ฌธ ์ƒ์„ฑ -> ์ฃผ๋ฌธ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜
        Order createOrder(Long memberId, String itemName, int itemPrice);
    
    }
    

    ์ฃผ๋ฌธ ์„œ๋น„์Šค ๊ตฌํ˜„์ฒด

    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();
    
        @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); //์ตœ์ข… ์ƒ์„ฑ๋œ ์ฃผ๋ฌธ ์ •๋ณด๋ฅผ ๋„˜๊ธด๋‹ค
        }
    }
    

     

    ์ฃผ๋ฌธ๊ณผ ํ• ์ธ ๋„๋ฉ”์ธ ์‹คํ–‰& ํ…Œ์ŠคํŠธ

    ์‹คํ–‰

    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.Order;
    import hello.core.order.OrderService;
    import hello.core.order.OrderServiceImpl;
    
    public class OrderApp {
        public static void main(String[] args) {
            MemberService memberService = new MemberServiceImpl();
            OrderService orderService = new OrderServiceImpl();
    
            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.order;
    
    import hello.core.member.Grade;
    import hello.core.member.Member;
    import hello.core.member.MemberService;
    import hello.core.member.MemberServiceImpl;
    import org.assertj.core.api.Assertions;
    import org.junit.jupiter.api.Test;
    
    public class OrderServiceTest {
    
        MemberService memberService = new MemberServiceImpl();
        OrderService orderService = new OrderServiceImpl();
    
        @Test
        void createOrder(){
            Long memberId = 1L; //long์œผ๋กœ ํ•˜๋ฉด null์ด ๋“ค์–ด๊ฐˆ ์ˆ˜ ์—†์Œ
            Member member = new Member(memberId, "memberA", Grade.VIP);
            memberService.join(member);
    
            Order order= orderService.createOrder(memberId, "itemA", 10000);
            Assertions.assertThat(order.getDiscountPrice()).isEqualTo((1000));
    
        }
    
    }
    

    ๋‹จ์œ„ํ…Œ์ŠคํŠธ(์Šคํ”„๋ง์ด๋‚˜ ์ปจํ…Œ์ด๋„ˆ ๋„์›€ ์—†์ด ์ž๋ฐ” ์ฝ”๋“œ๋กœ ํ…Œ์ŠคํŠธ ํ•˜๋Š” ๊ฒƒ)๋ฅผ ์ž˜ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค

     

    ๋‹จ์ถ•ํ‚ค

    commnad+n : genarate ๋‹จ์ถ•ํ‚ค

    command+a : ์ „์ฒด ์„ ํƒ

    option+enter : ๋ญ”๊ฐ€.. ์ž˜ ์•ˆ ๋  ๋•Œ… ๋นจ๊ฐ„์ค„ ์œ„์—์„œ ์น˜๋ฉด ๋ฌธ์ œ ํ•ด๊ฒฐํ•ด์คŒ

    command+shift+enter : ์„ธ๋ฏธ์ฝœ๋ก  ์ž๋™์™„์„ฑ

    psvm+enter : public static void main(String[] args) ๋‹จ์ถ•ํ‚ค

    command+option+v :

    sout+enter: System.*out*.println(); ๋‹จ์ถ•ํ‚ค

    soutv+enter: ๋ณ€์ˆ˜๋ฅผ ์œ„์—์„œ ์„ ํƒ ๊ฐ€๋Šฅ

    F2: ์˜ค๋ฅ˜๋‚œ ๊ณณ์œผ๋กœ ๋ฐ”๋กœ ์ด๋™

    ๋Œ“๊ธ€