/* ์ด ๊ธ์ ๊น์ํ๋์ ๊ฐ์๋ฅผ ๋ณด๊ณ ์ ๋ฆฌํ๋ ค๊ณ ์์ฑํ ๊ธ์ ๋๋ค.
๊ฐ์ธ์ ์ธ ๊ณต๋ถ๋ฅผ ์ํด ์ฌ๋ฆฌ๋ ๊ธ์ด๋ฏ๋ก ์ค๊ฐ ์ค๊ฐ ์ฝ๋๋ ์๋ต๋์์ต๋๋ค. */
์คํ๋ง ํต์ฌ ์๋ฆฌ - ๊ธฐ๋ณธํธ - ์ธํ๋ฐ | ๊ฐ์
์คํ๋ง ์ ๋ฌธ์๊ฐ ์์ ๋ฅผ ๋ง๋ค์ด๊ฐ๋ฉด์ ์คํ๋ง์ ํต์ฌ ์๋ฆฌ๋ฅผ ์ดํดํ๊ณ , ์คํ๋ง ๊ธฐ๋ณธ๊ธฐ๋ฅผ ํ์คํ ๋ค์ง ์ ์์ต๋๋ค., ์คํ๋ง ํต์ฌ ์๋ฆฌ๋ฅผ ์ดํดํ๊ณ , ์ฑ์ฅํ๋ ๋ฐฑ์๋ ๊ฐ๋ฐ์๊ฐ ๋์ด๋ณด์ธ์! ๐ข
www.inflearn.com
ํ์ ๋๋ฉ์ธ
1. ํ์ ๋๋ฉ์ธ ์ค๊ณ
ํ์ ๋๋ฉ์ธ ํ๋ ฅ ๊ด๊ณ
โพ ํด๋ผ์ด์ธํธ์ ์ญํ : ํ์์๋น์ค ํธ์ถ
โพ ํ์์๋น์ค์ ์ญํ : ํ์๊ฐ์ / ํ์์กฐํฌ ์ด ๋ ๊ฐ์ง์ ๊ธฐ๋ฅ
โพ ํ์์ ์ฅ์์ ์ญํ : ์ธ๊ฐ์ง ์ ์ฅ์ ์ค ํ๋๋ฅผ ์ ํํ์ฌ ํ์ ๊ด๋ฆฌ
[ DB ํ์ ์ ์ฅ์(์์ฒดDB) / ์ธ๋ถ ์์คํ ์ฐ๋ ํ์ ์ ์ฅ์ ]
์ด ๋ ์ค ์ด๋ค ์ ์ฅ์๋ฅผ ์ฌ์ฉํ ์ง ๋ฏธํ์ ์ด๊ธฐ ๋๋ฌธ์
๋ฉ๋ชจ๋ฆฌ ํ์ ์ ์ฅ์๋ฅผ ๋ง๋ค์ด ๊ฐ๋ฐ์ ์งํ(๋ก์ปฌ ๊ฐ๋ฐ, ํ ์คํธ ์งํ์ฉ)
ํ์ ํด๋์ค ๋ค์ด์ด ๊ทธ๋จ
โพ ํ์ ์๋น์ค = MemberService <interface>
โพ ํ์ ์๋น์ค์ ๊ตฌํ์ฒด = MemberServiceImpl
โพ ํ์ ์ ์ฅ์ = MemberRepository <interface>
โพ ํ์ ์ ์ฅ์์ ๊ตฌํ์ฒด = MemoryMemberRepository / DbMemberRepository
๐ก ์ฌ๊ธฐ์ ๊ถ๊ธํ๋ ์
: ์ ์ฅ์๋ ๋์ค์ ๊ต์ฒดํ๊ธฐ์ํด Interface๋ก ์ถ์ํ ํ๋๊ฑด ์ดํด๊ฐ ๊ฐ๋ Service๋ ๊ต์ฒด ๊ฐ๋ฅ์ฑ์ด ์๋๋ฐ ์ถ์ํ๋ฅผ ํ๋ ์ด์ ๋? ์ด ๊ถ๊ธํ๋๋ฐ ๋๊ตฐ๊ฐ๊ฐ ์ธํ๋ฐ์ ์ง๋ฌธ์ ํ๊ณ , ๊น์ํ๋์ด ๋ต๋ณํ๊ฒ ์์ด์ ์ฐธ์กฐ
๋๊ตฐ๊ฐ ์ด ์ง๋ฌธ์ ํด์ฃผ์ด์ผ ํ๋๋ฐ, ํ๊ณ ๊ธฐ๋ค๋ฆฌ๊ณ ์๋ ์ง๋ฌธ์
๋๋ค. ใ
ใ
์ ๊ฐ ๊ฐ์ฒด ์งํฅ ์ค๊ณ์ ์คํ๋ง ๋ง์ง๋ง์์ ๋ง์๋๋ ธ๋ ๋ด์ฉ์ด ๊ธฐ์ต๋์ค๊บผ์์.
* ์ด์์ ์ผ๋ก๋ ๋ชจ๋ ์ค๊ณ์ ์ธํฐํ์ด์ค๋ฅผ ๋ถ์ฌํ์
์ค๋ฌด ๊ณ ๋ฏผ
* ํ์ง๋ง ์ธํฐํ์ด์ค๋ฅผ ๋์
ํ๋ฉด ์ถ์ํ๋ผ๋ ๋น์ฉ์ด ๋ฐ์ํ๋ค.
* ๊ธฐ๋ฅ์ ํ์ฅํ ๊ฐ๋ฅ์ฑ์ด ์๋ค๋ฉด, ๊ตฌ์ฒด ํด๋์ค๋ฅผ ์ง์ ์ฌ์ฉํ๊ณ ,
ํฅํ ๊ผญ ํ์ํ ๋ ๋ฆฌํฉํฐ๋งํด์ ์ธํฐํ์ด์ค๋ฅผ ๋์ ํ๋ ๊ฒ๋ ๋ฐฉ๋ฒ์ด๋ค.
๊ฐ์์์๋ ์ด์์ ์ผ๋ก ์ญํ ๊ณผ ๊ตฌํ์ ๋ถ๋ฆฌํ๋ ๊ฒ์ ์ด์ ์ ๋ง์ถ์ด์ ์ด๋ฐ ๋ถ๋ถ๋ค๋ ๋ถ๋ฆฌํ์ต๋๋ค.
์ ๋ ์ค๋ฌด์์๋ ๊ต์ฒด ๊ฐ๋ฅ์ฑ์ด ์๋ ์๋น์ค ํด๋์ค๋ ๊ตฌ์ฒด ํด๋์ค๋ก ๋ฐ๋ก ๋ง๋๋ ๊ฒ์ ์ ํธํฉ๋๋ค^^
ํ์ ๊ฐ์ฒด ๋ค์ด์ด๊ทธ๋จ
โพ ๊ฐ์ฒด ๋ค์ด์ด ๊ทธ๋จ : ์ค์ ์๋ฒ์ ์ฌ๋ผ์์ ๋ ๊ฐ์ฒด๋ค์ ๋ฉ๋ชจ๋ฆฌ ์ฐธ์กฐ๋ฅผ ๊ทธ๋ฆฐ ๊ฒ
โพ ๊ฒฐ๊ณผ์ ์ผ๋ก ์ฐ๋ฆฌ๊ฐ ๋ง๋ค์ด์ผ ํ๋ ๊ทธ๋ฆผ
2. ํ์ ๋๋ฉ์ธ ๊ฐ๋ฐ
MemoryMemberRepository
public class MemoryMemberRepository implements MemberRepository{
private static Map<Long, Member> store = new HashMap<>();
@Override
public void save(Member member) {
store.put(member.getId(), member);
}
@Override
public Member findById(Long memberId) {
return store.get(memberId);
}
}
๐ก ๊ถ๊ธ์ฆ 1
: store๋ฅผ ๋ง๋ค ๋ static์ ์ฌ์ฉํ ์ด์ ๋?
static ์ ์ฌ์ฉํ๋ฉด ๊ฐ์ฒด๋ฅผ ์์ฑํ์ง ์๊ณ ํด๋์ค ์ด๋ฆ์ผ๋ก ์ง์ ์ ๊ทผํ ์ ์์ผ๋ฉฐ, ์ค๋ก์ง ๋จ ํ ๋ฒ๋ง ์์ฑ๋๊ธฐ ๋๋ฌธ์ ๋ชจ๋ ๊ฐ์ฒด์์ ๋์ผํ ๊ฐ์ผ๋ก ์ฌ์ฉํ ์ ์๋ค. ๋ฐ๋ผ์ ๋ค๋ฅธ ๊ฐ์ฒด ๊ฐ์ ๊ฐ์ ์ ๋ฌํ๊ฑฐ๋ ๊ณต์ ํ๋๋ฐ ์ฉ์ดํ๋ค.
์ด๋ฌํ static์ ํน์ง์ ์ด์ฉํ์ฌ ๋จ ํ๋์ Map์ ์ฌ์ฉํ๊ธฐ ์ํด static์ผ๋ก Map์ ์์ฑํ ๊ฒ.
๋ง์ฝ static์ ์ ๊ฑฐํ๋ค๋ฉด new MemberRepository(); ๋ฅผ ์์ฑํ ๋ ๋ง๋ค ์๋ก์ด Map์ด ์์ฑ๋์ด ๊ฐ์ฒด๋ง๋ค ๋ค๋ฅธ ๊ฐ์ Map์ ๊ฐ์ง๊ฒ ๋๋ค.
๐ก ๊ถ๊ธ์ฆ 2
: store๋ฅผ HashMap์ผ๋ก ์์ฑํ๋๋ฐ ์ผ๋ฐ์ ์ผ๋ก ๋์์ฑ ์ด์๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ConcurrentHashMap์ผ๋ก ์์ฑํ๋๊ฒ ์ข๋ค๊ณ ํ์ จ๋ค. ์์ ๋ฅผ ๋จ์ํ๊ฒ ํ๊ธฐ ์ํด HashMap์ผ๋ก ์์ฑํ๋๋ฐ ๋์ ์ฐจ์ด์ ์?
HashMap๊ณผ ConcurrentHashMap์ ๋๋ค 'key-value' ํํ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ์๋ฃ๊ตฌ์กฐ์ด๋ค.
HashMap
- ๋ฐ์ดํฐ์ ์ฝ์ , ์ญ์ , ๊ฒ์๋ฑ์ ์ฐ์ฐ์ด ๋น ๋ฅด๋ค
- null ๊ฐ์ ์ ์ฅํ ์ ์๋ค
- ์ฑ๊ธ์ค๋ ๋ ํ๊ฒฝ์์ ์์ ํ๊ฒ ์ฌ์ฉํ ์ ์๋ค
ConcurrentHashMap
- ๋ด๋ถ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ถํ ํ์ฌ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝํด์ HashMap๋ณด๋ค ๋ ๋น ๋ฅธ ์๋๋ก ๋์ํ๋ค.
- null ๊ฐ์ ์ ์ฅํ ์ ์๋ค
- ๋ฉํฐ์ค๋ ํธ ํ๊ฒฝ์์ ์์ ํ๊ฒ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ ์ฌ๋ฌ ์ค๋ ๋์์ ๋์์ ์ ๊ทผํด๋ ์ผ๊ด์ฑ์ ์ ์งํ๋ค.
MemberServiceImpl
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository = new MemoryMemberRepository();
@Override
public void join(Member member) {
memberRepository.save(member);
}
@Override
public Member findMember(Long memberId) {
return null;
}
}
๐ก ๊ถ๊ธ์ฆ 1
: memberRepository๋ฅผ ๋ง๋ค ๋ final๋ก ์ ์ธํ ์ด์ ?
โพ ๋ถ๋ณ์ฑ(Immutability): final ํ๋๋ ํ ๋ฒ ์ด๊ธฐํ๋๋ฉด ๊ฐ์ ๋ณ๊ฒฝํ ์ ์๋ค. ์ด๊ฒ์ ํ๋์ ๋ํ ์์ ์ฑ์ ์ ๊ณตํ๋ฉฐ, ํ๋ ๊ฐ์ ๋ณดํธํ๋ค. memberRepository๊ฐ ํ ๋ฒ ์ค์ ๋๋ฉด ๋ค๋ฅธ ๊ฐ์ฒด๋ก ๋ณ๊ฒฝ๋์ง ์๋๋ก ๋ณด์ฅํ๋ค.
โพ ์ค๋ ๋ ์์ ์ฑ(Thread Safety): final ํ๋๋ ๋ค์ค ์ค๋ ๋ ํ๊ฒฝ์์ ์์ ํ๊ฒ ์ฌ์ฉ๋๋ค. ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ memberRepository๋ฅผ ์์ ํ๋ ค๊ณ ์๋ํ๋ ๊ฒ์ ๋ฐฉ์งํ๋ฉฐ, ๋์ ์ ๊ทผ์ ๋ํ ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ๋ค.
โพ ๊ฐ๋ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ: final ํค์๋๋ฅผ ์ฌ์ฉํ๋ฉด ์ฝ๋์ ์๋๊ฐ ๋ช ํํด์ง๋ค. memberRepository๊ฐ ํ ๋ฒ ์ค์ ๋๊ณ ๋ณ๊ฒฝ๋์ง ์๋๋ค๋ ์ฌ์ค์ ์ฝ๋๋ฅผ ์ฝ๋ ์ฌ๋์๊ฒ ์ค์ํ ์ ๋ณด๋ฅผ ์ ๋ฌํ๋ค.
โพ ์ค๋ฅ ๋ฐฉ์ง: final๋ก ์ ์ธ๋ ํ๋๋ ์ปดํ์ผ ์๊ฐ์ ํ ๋ฒ ์ด๊ธฐํ๋๋ฉฐ, ๋ฐํ์ ์ค์ ๋ค์ ์ค์ ๋๋ ์ค๋ฅ๋ฅผ ๋ฐฉ์งํ๋ค.
3. ํ ์คํธ ์ฝ๋ ์์ฑ
โพ ๋์ค์ ๋น๋ํ๋ฉด ํ ์คํธ ์ฝ๋๋ ๋น ์ง๋ค๊ณ ํจ!
MemberServiceTest
package hello.core.member;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
public class MemberServiceTest {
@Test
void join() {
MemberService memberService = new MemberServiceImpl();
// given
Member member = new Member(1L, "memberA", Grade.VIP);
// when
memberService.join(member);
Member findMember = memberService.findMember(1L);
// then
Assertions.assertThat(member).isEqualTo(findMember);
}
}
โพ Assertions Importํ ๋ "org.assertj.core.api.Assertions" ์ด๊ฑธ๋ก!
๐ก ๊ถ๊ธ์ฆ 1
: Assertions์ ๊ธฐ๋ฅ๊ณผ assertThat์ ๊ธฐ๋ฅ ์ข ๋ฅ
Assertions์ ํ ์คํธ ์ฝ๋์์ ์ฌ์ฉ๋๋ฉฐ ํน์ ์กฐ๊ฑด์ด ์ฐธ์ด์ด์ผ ํ ์คํธ๊ฐ ๊ณ์ ์งํ๋๋๋ก ํ๋ ๊ธฐ๋ฅ์ด๋ฉฐ assertThat์ ๋ค์ํ ๋น๊ต ๋ฐ ๊ฒ์ฆ์์ ์ ์ํํ ๋ ์ฌ์ฉํ๋ค.
assertThat ๋ฉ์๋ ์ข ๋ฅ
String ex1 = "hello wolrd";
String ex2 = "hello wolrd";
โพ assertThat(ex1).isEqualTo(ex2); / isNotEqualTo(ex1); : ๋ ๊ฐ์ด ๊ฐ์์ง / ๋ค๋ฅธ์ง ๋น๊ต
โพ assertThat(ex1).isNull(); / isNotNull(); : ๊ฐ์ด null์ธ์ง / null์ด ์๋์ง ํ์ธ
โพ assertThat(ex1).istrue(); / isfalse(); : ๊ฐ์ด true์ธ์ง / false์ธ์ง ํ์ธ
โพ assertThat(ex1).startWith("hello") / endsWith("wolrd") : ๋ฌธ์์ด์ ์์, ๋ ํ์ธ
โพ assertThat(ex1).contains("hello") : ๋ฌธ์์ด ํน์ ๋ถ๋ถ์ ํฌํจ๋๋์ง ํ์ธ
๋ฑ๋ฑ ๋ง์ผ๋๊น ์ฐพ์๋ณด๊ธฐ
4. ์ค๊ณ์ ๋ฌธ์ ์
โพ ์ด ์ฝ๋๋ ์์กด๊ด๊ณ๊ฐ ์ธํฐํ์ด์ค ๋ฟ๋ง ์๋๋ผ ๊ตฌํ๊น์ง ๋ชจ๋ ์์กดํ๋ ๋ฌธ์ ์ ์ด ์์
private final MemberRepository memberRepository = new MemoryMemberRepository();
์ฌ๊ธฐ์ MemberRepository๋ ์ธํฐํ์ด์ค์ ์์กดํ์ง๋ง ์ค์ ํ ๋นํ๋ ๋ถ๋ถ์ ๊ตฌํ์ฒด๋ฅผ ์์กดํ๊ณ ์์
์ถ์ํ์๋ ์์กดํ๊ณ ๊ตฌํ์ฒด์๋ ์์กดํ๊ณ ์๋ ์ํ = DIP ์๋ฐ
โ ํด๊ฒฐ ๋ฐฉ์์ '์ฃผ๋ฌธ'๊น์ง ๋ง๋ค๊ณ ๋์ ์ค๋ช ํด์ฃผ์ ๋ค๊ณ ํจ.