[Spring ๊ธฐ๋ณธ] 3. ์คํ๋ง ํต์ฌ ์๋ฆฌ ์ดํด2- ๊ฐ์ฒด ์งํฅ ์๋ฆฌ ์ ์ฉ
์๋ ํ์ธ์!
์ ๋ฒ ์น์ ์์ ํ๋ ๊ฒ์ ์ด์ด ์๋ก์ด ํ ์ธ ์ ์ฑ (์ ๋ฅ ํ ์ธ ์ ์ฑ )์ ๊ฐ๋ฐํด๋ณด๊ณ ์คํ๋ง์ผ๋ก ์ ํ์ ํด๋ณด๊ฒ ์ต๋๋ค!
๊ณ ๊ณ !!

1. ์๋ก์ด ํ ์ธ ์ ์ฑ ๊ฐ๋ฐ - ์ ๋ฅ ํ ์ธ ์ ์ฑ (RateDiscountPolicy)
์ ๋ฒ ์น์ ์์ ํ๋ ๊ฒ๋ค์ ์ด์ด ์๋ก์ด ํ ์ธ ์ ์ฑ ์ ํ์ฅํด๋ณด๊ฒ ์ต๋๋ค.
<์ํฉ>
- ์
๋ ๊ธฐํ์: ์๋น์ค ์คํ ์ง์ ์ ํ ์ธ ์ ์ฑ
์ ์ง๊ธ์ฒ๋ผ ๊ณ ์ ๊ธ์ก ํ ์ธ์ด ์๋๋ผ ์ข ๋ ํฉ๋ฆฌ์ ์ธ ์ฃผ๋ฌธ ๊ธ์ก ๋น ํ ์ธํ๋ ์ ๋ฅ (%) ํ ์ธ์ผ๋ก ๋ณ๊ฒฝํ๊ณ ์ถ์ต๋๋ค.
์๋ฅผ ๋ค์ด์ ๊ธฐ์กด ์ ์ฑ ์ VIP๊ฐ 10,000์์ ์ฃผ๋ฌธํ๋ 20,000์์ ์ฃผ๋ฌธํ๋ ํญ์ 1,000์์ ํ ์ธํ๋๋ฐ, ์ด๋ฒ์ ์๋ก ๋์จ ์ ์ฑ ์ 10%๋ก ์ง์ ํด๋๋ฉด ๊ณ ๊ฐ์ด 10,000์ ์ฃผ๋ฌธ ์ 1,000์์ ํ ์ธํด์ฃผ๊ณ , 20,000์ ์ฃผ๋ฌธ ์ 2,000์์ ํ ์ธํด์ฃผ๋ ๊ฒ์ ๋๋ค. - ์์ง ๊ฐ๋ฐ์: ์ ๊ฐ ์ฒ์๋ถํฐ ๊ณ ์ ๊ธ์ก ํ ์ธ์ ์๋๋ผ๊ณ ํ์ง ์์์ต๋๊น..
- ์ ๋ ๊ธฐํ์: ์ ์์ผ ์ํํธ์จ์ด ๊ฐ๋ฐ ์ ์ธ ๋ชจ๋ฆ ๋๊น? ๊ณํ์ ๋ฐ๋ฅด๊ธฐ๋ณด๋ค ๋ณํ์ ๋์ํ๊ธฐ๋ฅผ...
- ์์ง ๊ฐ๋ฐ์: ... (ํ์ง๋ง ๋ ์ ์ฐํ ์ค๊ณ๊ฐ ๊ฐ๋ฅํ๋๋ก ๊ฐ์ฒด์งํฅ ์ค๊ณ ์์น์ ์ค์ํ์ง ํํ)
์ ์์ผ ์ํํธ์จ์ด ๊ฐ๋ฐ ์ ์ธ
๊ณต์ ๊ณผ ๋๊ตฌ๋ณด๋ค ๊ฐ์ธ๊ณผ ์ํธ์์ฉ์
ํฌ๊ด์ ์ธ ๋ฌธ์๋ณด๋ค ์๋ํ๋ ์ํํธ์จ์ด๋ฅผ
๊ณ์ฝ ํ์๋ณด๋ค ๊ณ ๊ฐ๊ณผ์ ํ๋ ฅ์
๊ณํ์ ๋ฐ๋ฅด๊ธฐ๋ณด๋ค ๋ณํ์ ๋์ํ๊ธฐ๋ฅผ
์์ง ๊ฐ๋ฐ์๊ฐ ์ ๋ง ๊ฐ์ฒด์งํฅ ์ค๊ณ ์์น์ ์ ์ค์ํ์๊น์?
๊ทธ๋ฆฌ๊ณ , ์ด๋ฒ์๋ ์ฃผ๋ฌธํ ๊ธ์ก์ %๋ฅผ ํ ์ธํด์ฃผ๋ ์๋ก์ด ์ ๋ฅ ํ ์ธ ์ ์ฑ ์ ์ถ๊ฐํด๋ณด๊ฒ ์ต๋๋ค.
์ฐ์ ์น์ 2์์ ํ๋ ์ฝ๋๋ฅผ ๋ค์ ์ผ์ ๊ธฐ์กด์ ๋ง๋ค์๋ discount๋ผ๋ ํจํค์ง์ RateDiscountPolicy๋ผ๋ ํด๋์ค๋ฅผ ์ถ๊ฐํด๋ณด๊ฒ ์ต๋๋ค.
DiscountPolicy๋ผ๋ ์ธํฐํ์ด์ค์ ๋ํ ๊ตฌํ์ฒด์ด๋ฏ๋ก ์ ์๋ ๋๊ฐ์ด implements๋ฅผ ํ๊ณ Alt + Enter๋ฅผ ๋๋ฌ์ ๋ฉ์๋ ๊ตฌํ(์ค๋ฒ๋ผ์ด๋)์ ํด๋ณด๊ฒ ์ต๋๋ค.
package hello.core.discount;
import hello.core.member.Grade;
import hello.core.member.Member;
public class RateDiscountPolicy implements DiscountPolicy{
private int discountPercent = 10; //10% ํ ์ธ
@Override
public int discount(Member member, int price) {
if(member.getGrade() == Grade.VIP) {
return price * discountPercent /100;
}
else {
return 0;
}
}
}
10% ํ ์ธ์ด๋ฏ๋ก private int discountPercent = 10;์ด๋ ์ฝ๋๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
๋ํ, VIP ๋ฑ๊ธ๋ง ํ ์ธ์ ๋ฐ์ ์ ์์ผ๋ฏ๋ก if๋ฌธ์ ์ฌ์ฉํ์ต๋๋ค.
๊ทผ๋ฐ ์ด ์... ๊ณผ์ฐ ์ ๋๋ ๊ฑธ๊น์?
ํ ์คํธ๋ฅผ ํด๋ณด๊ฒ ์ต๋๋ค.
์ ์์ฒ๋ผ ์ผ์ผ์ด ํ ์คํธ ํด๋์ค ๋ง๋ค๊ณ ํ๊ธฐ ํ๋ค์์์.
๊ทธ๋์ ๋จ์ถํค๋ฅผ ์ด์ฉํด๋ณผ๊ฒ์.
์๋์ฐ๋ ctrl + shift + t, ๋งฅ์ command + shift + t๋ฅผ ๋๋ฅด๋ฉด
์ด๋ ๊ฒ ๋น๋๋ค. ์ ํ ์คํธ ์์ฑ์ ๋๋ฌ๋ณด๊ฒ ์ต๋๋ค.
ํ ์คํธ๋ JUnit5๋ก ๋๋๊ณ ํด๋์ค ์ด๋ฆ์ ๊ธฐ์กด์ RateDiscountPolicy์์ ๋ค์ Test๋ฅผ ๋ถํ๋๋ค.
๊ทธ๋ฌ๊ณ ๋ฐ์ ๊ฑฐ๋ ์๋ฌด๊ฒ๋ ๊ฑด๋ค์ง ์๊ณ , ํ์ธ์ ๋๋ฅด๋ฉด ์๋ก์ด ํ ์คํธ ํด๋์ค๊ฐ ์์ฑ๋ฉ๋๋ค.
ํ ์คํธ ํด๋์ค ์์ฑ๋๊ฑฐ ๋ณด์ด์๋์?
๊ทธ๋ผ ์ฌ๊ธฐ์ ํ ์คํธ๋ฌธ์ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
package hello.core.discount;
import hello.core.member.Grade;
import hello.core.member.Member;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
class RateDiscountPolicyTest {
RateDiscountPolicy discountPolicy = new RateDiscountPolicy();
@Test
@DisplayName("VIP๋ 10% ํ ์ธ์ด ์ ์ฉ๋์ด์ผ ํ๋ค.") //ํ๊ธ๋ก ์ด๋ฆ์ ์ธ ์ ์์
void vip_o() {
//given //ํ
์คํธ ํ๊ฒฝ์ ๊ฐ์ถ๋ ๋จ๊ณ, ์ด๋ฐ ํ๊ฒฝ์ด ์ฃผ์ด์ก์ ๋
Member member = new Member(1L, "memberVIP", Grade.VIP);
//when //ํ
์คํธ ํ ์ํฉ์ ์งํํ๋ ๋จ๊ณ, ์ด๋ ๊ฒ ํ์ ๋
int discount = discountPolicy.discount(member, 10000);
//then //์์ํ ๋๋ก ์ ์๋ํ๋์ง ํ
์คํธ, ์ด๋ ๊ฒ ๋๋ค
Assertions.assertThat(discount).isEqualTo(1000);
}
}
@Test๋ฅผ ์ฌ์ฉํด์ ํ ์คํธ๋ฌธ์ ๋ง๋ญ๋๋ค.
๊ทธ๋ฆฌ๊ณ , @DisplayName("aa")์ JUnit5 ์ด์๋ถํฐ ์ง์ํ๋๋ฐ, ""์์ ๋ค์ด๊ฐ์๋ ์ค๋ช (์ด๋ฆ)์ด ํ ์คํธ ๊ฒฐ๊ณผ ๋ฐ์ ๋น๋๋ค.
ํ๊ธ๋ก ์ด๋ฆ์ ์ธ ์ ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ , ๋๊ฐ์ด given, when, then์ ํด์ค๊ฑด๋ฐ์.
- Member member = new Member(1L, "memberVIP", Grade.VIP);
- ํ ์คํธ ์ "memberVIP"๋ผ๋ ๋ฉค๋ฒํ ๋ณ์๋ฅผ ์์ฑํฉ๋๋ค.
- ํ์ ๊ฐ์ ์ ์ ํ์ ๊ฐ์ ์ฐฝ์ ํ์์ ์ ๋ณด๋ค์ ์ ์ด๋๊ธฐ๋ง ํ ์ํ์ ๋น์ทํฉ๋๋ค.
- int discount = discountPolicy.discount(member, 10000);
- VIP ๋ฑ๊ธ์ธ ์ด ํ์์ด 10,000์์ง๋ฆฌ ๋ฌผ๊ฑด์ ๊ตฌ์ ํ์ ๋ ํ ์ธ๋๋ ๊ธ์ก์ int ๋ณ์๋ก ์ง์ ํ์ต๋๋ค.
- Assertions.assertThat(discount).isEqualTo(1000);
- Assertions๋ JUnit์์ ์ ๊ณตํ๋ ํ
์คํธ ๋ฉ์๋๋ค์ ์งํฉ ํด๋์ค์
๋๋ค.
๊ทธ ์ค ์ ํฌ๋ ๋น๊ต ๋์์ ์ง์ ํ ์ ์๋ assertThat()์ ์ฌ์ฉํฉ๋๋ค. - ์ ํฌ๋ 2๋ฒ์งธ when์์ ๋์จ ๋ณ์ discount๋ฅผ ๋น๊ต ๋์์ ์ง์ ํ์ต๋๋ค.
- ํด๋น ๋ณ์(ํ ์ธ๋๋ ๊ธ์ก)๊ฐ 1000์ด ๋ง์์ผ ํ ์คํธ๊ฐ ์ฑ๊ณตํฉ๋๋ค.
- Assertions๋ JUnit์์ ์ ๊ณตํ๋ ํ
์คํธ ๋ฉ์๋๋ค์ ์งํฉ ํด๋์ค์
๋๋ค.
๊ทธ๋ผ ํ ์คํธ๋ฅผ ์คํํด๋ณด๊ฒ ์ต๋๋ค.
@DisplayName์ ํตํด ์ด๋ฆ์ด ๋จ๊ณ , ํ ์คํธ๊ฐ ์ฑ๊ณตํ๋ค๊ณ ๋น๋๋ค.
์์ โ๏ธํ์ ์ ๋๋ฅด๋ฉด ํ ์คํธ ๊ฒฐ๊ณผ ๋ฐ์ ์๋ ๋ด์ฉ ์ ๋จ๋๋ผ๊ตฌ์. ์ ๋ง ๊ทธ๋ฐ๊ฑด์ง ๋ชจ๋ฅด๊ฒ ๋๋ฐ ์ํผ ์ ๋์ค๋ฉด ์ ์ฒดํฌ ํ์ ๋๋ฌ๋ณด์ธ์. ๋์ฌ ๊ฒ๋๋ค.
๊ทธ๋ฐ๋ฐ ์ฌ๊ธฐ์ ์ค์ํ๊ฑด ํ ์คํธ๋ฌธ์ ๊ผญ ์คํจํ๋ ํ ์คํธ๋ฌธ๋ ๋ง๋ค์ด๋ด์ผํ๋ค๋ ๊ฒ์ ๋๋ค.
์คํจํ๋ ํ ์คํธ๋ฌธ๋ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
@Test
@DisplayName("VIP๊ฐ ์๋๋ฉด ํ ์ธ์ด ์ ์ฉ๋์ง ์์์ผ ํ๋ค.")
void vip_x() {
//given
Member member = new Member(2L, "memberBASIC", Grade.BASIC);
//when
int discount = discountPolicy.discount(member, 10000);
//then
Assertions.assertThat(discount).isEqualTo(1000);
}
์๊น ํ ์คํธ๋ฌธ๊ณผ ์ฝ๋๋ ๋น์ทํ๋ฐ VIP๊ฐ ์๋์ด์ผ ํ๋ฏ๋ก ๋ฑ๊ธ๊ณผ ์ด๋ฆ์ BASIC์ผ๋ก ๋ฐ๊ฟ๋ณด๊ฒ ์ต๋๋ค.
์ด๋ฌ๋ฉด ๊ฒฐ๊ณผ๊ฐ ์ด๋ป๊ฒ ๋์ฌ๊น์?
์ด๋ ๊ฒ ์ค๋ฅ๊ฐ ๋น๋๋ค.
๋ถ๋ช ๊ธฐ๋ํ ๊ฐ์ 1,000์ธ๋ฐ ์ค์ ๋ก๋ 0์ด ๋์์ ์ค๋ฅ๊ฐ ๋ด๋ค๊ณ ๋์์์ต๋๋ค.
๊ทธ๋ผ ์ด ํ ์คํธ๋ฌธ๋ ํ ์คํธ ์ฑ๊ณตํ๋๋ก ๋ฐ๊ฟ๋ณด๊ฒ ์ต๋๋ค.
Assertions.assertThat(discount).isEqualTo(1000);
์ด ๋ฌธ์ฅ์์ 1000์ 0์ผ๋ก ๋ฐ๊พธ๋ฉด ๋ฉ๋๋ค.
๋ฐ๊พผ ์ํ์์ ํ ์คํธ ์คํ์ ํด๋ณด๊ฒ ์ต๋๋ค.
ํ ์คํธ ์ฑ๊ณตํ์ต๋๋ค.
์ด๋ฒ์ ํ ์คํธ๋ฌธ 2๊ฐ๋ฅผ ํ ๋ฒ์ ๋๋ ค๋ณด๊ฒ ์ต๋๋ค.
์ญ์๋ ๋ ๋ค ์ฑ๊ณตํ๋ค๊ณ ๋์ต๋๋ค.
์ค์ํ ๊ฒ์ด ํ๋ ์๋๋ฐ, ์์ ํ ์คํธ๋ฌธ์์ Assertions ์ชฝ์์ ์๋์ฐ ๊ธฐ์ค Alt + Enter (๋งฅ์ ์ต์ + Enter) ๋๋ฅด๊ณ
์ฌ์ง์ฒ๋ผ static import ๋๋ฅด๋ฉด
Assertions๊ฐ ์ฌ๋ผ์ง๊ณ ์ด๋ ๊ฒ ์ฝ๋๊ฐ ๊ฐ๊ฒฐํด์ง๋๋ค.
๋ํ, ์์ import๋ฌธ์์ import static org.assertj.core.api.Assertions.*;์ด ์๊น๋๋ค.
static import๋ ์๋ฐ ๊ธฐ๋ณธ ๋ฌธ๋ฒ์ ๋๋ค.
2. ์๋ก์ด ํ ์ธ ์ ์ฑ ์ ์ฉ๊ณผ ๋ฌธ์ ์ - ์ ๋ฅ ํ ์ธ ์ ์ฑ (RateDiscountPolicy)์ผ๋ก ๋ณ๊ฒฝ
๋ฐฉ๊ธ ์ถ๊ฐํ ํ ์ธ ์ ์ฑ ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ฉํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
ํ ์ธ ์ ์ฑ ์ ๋ณ๊ฒฝํ๋ ค๋ฉด ํด๋ผ์ด์ธํธ์ธ OrderServiceImpl ์ฝ๋๋ฅผ ๊ณ ์ณ์ผ ํฉ๋๋ค.
public class OrderServiceImpl implements OrderService{
...
//private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
...
}
์๋๋ ์ ์ก ํ ์ธ ์ ์ฑ ์ผ๋ก ๋์ด์์๊ธฐ ๋๋ฌธ์ FixDiscountPolicy๋ฅผ ์ฌ์ฉํ์๋๋ฐ, ์ด์ ์ ๋ฅ ํ ์ธ ์ ์ฑ ์ผ๋ก ์ ์ฉํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ FixDiscountPolicy ์๋ฆฌ์ RateDiscountPolicy๋ก ๋ฐ๊ฟ๋๋ค.

๊ทธ๋ฐ๋ฐ ์ด๋ ๊ฒ ํ๋๋ฐ ๋ฌธ์ ์ ์ด ๋ฐ์ํ์ต๋๋ค.
<๋ฌธ์ ์ ๋ฐ๊ฒฌ>
1. ์ญํ ๊ณผ ๊ตฌํ์ ์ถฉ์คํ๊ฒ ๋ถ๋ฆฌํ์ต๋๋ค. -> OK
2. ๋คํ์ฑ๋ ํ์ฉํ๊ณ , ์ธํฐํ์ด์ค์ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ๋ถ๋ฆฌํ์ต๋๋ค. -> OK
3. OCP, DIP ๊ฐ์ ๊ฐ์ฒด์งํฅ ์ค๊ณ ์์น์ ์ถฉ์คํ ์ค์ํ์ต๋๋ค. -> ๊ทธ๋ ๊ฒ ๋ณด์ด์ง๋ง ์ฌ์ค์ X
3-1(์ค์). DIP: ์ฃผ๋ฌธ์๋น์ค ํด๋ผ์ด์ธํธ(OrderServiceImpl)๋ DiscountPolicy ์ธํฐํ์ด์ค์ ์์กดํ๋ฉด์ DIP๋ฅผ ์งํจ ๊ฒ ๊ฐ์๋ฐ์..?
-> ํด๋์ค ์์กด ๊ด๊ณ๋ฅผ ๋ถ์ํด๋ณด๋ฉด... ์ถ์(์ธํฐํ์ด์ค) ๋ฟ๋ง ์๋๋ผ ๊ตฌ์ฒด(๊ตฌํ) ํด๋์ค์๋ ์์กดํ๊ณ ์๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
--> ์ถ์(์ธํฐํ์ด์ค) ์์กด: DiscountPolicy
--> ๊ตฌ์ฒด(๊ตฌํ) ํด๋์ค: FixDiscountPolicy, RateDiscountPolicy
3-2(์ค์). OCP: ๋ณ๊ฒฝํ์ง ์๊ณ ํ์ฅํ ์ ์๋ค๊ณ ํ๋๋ฐ์..?
--> ์ง๊ธ ์ฝ๋๋ ๊ธฐ๋ฅ์ ํ์ฅํด์ ๋ณ๊ฒฝํ๋ฉด, ํด๋ผ์ด์ธํธ ์ฝ๋์ ์ํฅ์ ์ค๋๋ค. ๋ฐ๋ผ์, OCP๋ฅผ ์๋ฐํฉ๋๋ค.
์ ํด๋ผ์ด์ธํธ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํด์ผ ํ ๊น์?
ํด๋์ค ๋ค์ด์ด๊ทธ๋จ์ผ๋ก ์์กด๊ด๊ณ๋ฅผ ๋ถ์ํด๋ณผ ์ ์์ต๋๋ค.
- ๊ธฐ๋ํ๋ ์์กด๊ด๊ณ
์ง๊ธ๊น์ง ๋จ์ํ DiscountPolicy ์ธํฐํ์ด์ค๋ง ์์กดํ๋ค๊ณ ์๊ฐํ์ต๋๋ค.
- ์ค์ ์์กด๊ด๊ณ
๊ทผ๋ฐ ์ค์ ๋ก ๊น ๋ณด๋ฉด ํด๋ผ์ด์ธํธ์ธ OrderServiceImpl์ด DiscountPolicy ์ธํฐํ์ด์ค ๋ฟ๋ง ์๋๋ผ
FixDiscountPolicy์ธ ๊ตฌ์ฒด ํด๋์ค๋ ํจ๊ป ์์กดํ๊ณ ์์ต๋๋ค.
์ค์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ์์กดํ๊ณ ์์ต๋๋ค. DIP ์๋ฐ!!
- ์ ์ฑ ๋ณ๊ฒฝ
๊ทธ๋์, FixDiscountPolicy๋ฅผ RateDiscountPolicy๋ก ๋ณ๊ฒฝํ๋ ์๊ฐ, OrderServiceImpl์ ์์ค ์ฝ๋๋ ํจ๊ป ๋ณ๊ฒฝํด์ผ ํฉ๋๋ค. OCP ์๋ฐ!!

Q. ๊ทธ๋ผ ์ด๋ป๊ฒ ํ๋ฉด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์๊น์?
A. ํด๋ผ์ด์ธํธ ์ฝ๋์ธ OrderServiceImpl์ DiscountPolicy์ ์ธํฐํ์ด์ค ๋ฟ๋ง ์๋๋ผ ๊ตฌ์ฒด ํด๋์ค๋ ํจ๊ป ์์กดํฉ๋๋ค.
๊ทธ๋์, ๊ตฌ์ฒด ํด๋์ค๋ฅผ ๋ณ๊ฒฝํ ๋ ํด๋ผ์ด์ธํธ ์ฝ๋๋ ํจ๊ป ๋ณ๊ฒฝํด์ผ ํฉ๋๋ค,
๊ทผ๋ฐ ์ด๋ฌ๋ฉด DIP ์๋ฐ์ด๋ฏ๋ก, ์ถ์(์ธํฐํ์ด์ค)์๋ง ์์กดํ๋๋ก ์์กด๊ด๊ณ๋ฅผ ๋ณ๊ฒฝํด์ผ ํฉ๋๋ค.
์ธํฐํ์ด์ค์๋ง ์์กดํ๋๋ก ์ค๊ณ์ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
- ์ธํฐํ์ด์ค์๋ง ์์กดํ๋๋ก ์ค๊ณ๋ฅผ ๋ณ๊ฒฝ
public class OrderServiceImpl implements OrderService{
...
//private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
private DiscountPolicy discountPolicy;
...
}
์ด๋ ๊ฒ ์ธํฐํ์ด์ค์๋ง ์์กดํ๋๋ก ์ค๊ณ์ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ์ต๋๋ค.
ํ์ง๋ง, ์ด๋ ๊ฒ ํ๋ฉด OrderServiceImpl์์ ์ฌ์ฉํ discountPolicy๊ฐ ์ ์ก ํ ์ธ ์ ์ฑ ์ผ์ง ์ ๋ฅ ํ ์ธ ์ ์ฑ ์ผ์ง ์ง์ ๋์ด ์์ง ์๊ณ , ์์ ๊ฐ์ ๋ฃ์ง ์๋ค๋ณด๋ null ๊ฐ์ด ๋ค์ด๊ฐ์ต๋๋ค. (=ํ๊ณ ๋ค์ ๋ญ๊ฐ ์๊ธฐ ๋๋ฌธ์)
์ค์ ๋ก ์คํ์ ํด๋ณด๋ฉด NPE(Null Pointer Exception)๊ฐ ๋ฐ์ํฉ๋๋ค.

NPE๊ฐ ์ ํฐ์ก์๊น์?
public class OrderServiceTest {
MemberService memberService = new MemberServiceImpl();
OrderService orderService = new OrderServiceImpl();
@Test
void createOrder() {
Long memberId = 1L;
Member member = new Member(memberId, "์์", Grade.VIP);
memberService.join(member);
Order order = orderService.createOrder(memberId, "์ด์ฝ๋ฆฟ", 10000);
Assertions.assertThat(order.getDiscountPrice()).isEqualTo(1000);
}
}
ํ์ฌ OrderServiceTest ํ ์คํธ ์ฝ๋์ ๋๋ค.
ํ ์คํธ ํจ์์ธ createOrder()์์ .createOrder ํจ์๊ฐ ์ด๋์์ ์ฐ์๋์ง ํ ๋ฒ ๋ค์ด๊ฐ๋ณผ๊ฒ์.
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository = new MemoryMemberRepository();
private 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์์ ์ฌ์ฉ์ด ๋์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ฌ๊ธฐ์์ int discountPrice = discountPolicy.discount(member, itemPrice);๊ฐ ๋ฌธ์ ์ ๋๋ค.
๋ฐ์์ discountPolicy๊ฐ ๋ถ๋ช ์ฌ์ฉ๋์๋๋ฐ ์๊น ์ ํฌ๊ฐ ์ผ๋ ๋ฌธ์ฅ์ ๋ณด๋ฉด discountPolicy๊ฐ null์์ ์ ์ ์์ต๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด ๋๊ตฐ๊ฐ๊ฐ ํด๋ผ์ด์ธํธ์ธ OrderServiceImpl์ DiscountPolicy์ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ๋์ ์์ฑํ๊ณ ์ฃผ์ ํด์ฃผ์ด์ผ ํฉ๋๋ค.
=> ์ง๊ธ ํ์ฌ๊น์ง์ ์ํฉ: DIP๋ ์ง์ผฐ์ผ๋, NPE๊ฐ ํฐ์ง.
3. ๋ฌธ์ ์ ํด๊ฒฐ ๋ฐฉ๋ฒ - ์ ๋ฅ ํ ์ธ ์ ์ฑ ์๊ธฐ ์
์์์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด ๋๊ตฐ๊ฐ๊ฐ ํด๋ผ์ด์ธํธ์ธ OrderServiceImpl์ DiscountPolicy์ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ๋์ ์์ฑํด์ฃผ๊ณ ์ฃผ์ ํด์ค์ผ ํ๋ค๊ณ ํ์ต๋๋ค.
์ง๊ธ๋ถํฐ ์ด ์ญํ ์ ๋ํด์ ์ค๋ช ํ๊ณ ์ ์ฉํด๋ณด๊ฒ ์ต๋๋ค.
3-1. ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ
์ ํ๋ฆฌ์ผ์ด์ ์ ํ๋์ ๊ณต์ฐ์ด๋ผ๊ณ ์๊ฐํด๋ณด๊ฒ ์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ , ๊ฐ๊ฐ์ ์ธํฐํ์ด์ค๋ฅผ ๋ฐฐ์ญ(๋ฐฐ์ฐ ์ญํ )์ด๋ผ๊ณ ์๊ฐํด๋ณด๊ฒ ์ต๋๋ค.
๊ทธ๋ผ ์ค์ ๋ฐฐ์ญ ๋ง๋ ๋ฐฐ์ฐ๋ฅผ ์ ํํ๋ ๊ฒ์ ๋๊ฐ ํ ๊น์?
๋ก๋ฏธ์ค์ ์ค๋ฆฌ์ฃ ๊ณต์ฐ์ ํ๋ฉด ๋ก๋ฏธ์ค ์ญํ ์ ๋๊ฐ ํ ์ง ์ค๋ฆฌ์ฃ ์ญํ ์ ๋๊ฐ ํ ์ง๋ ๋ฐฐ์ฐ๋ค์ด ์ ํ๋ ๊ฒ์ด ์๋๋๋ค.
๋ฐฐ์ฐ๊ฐ ์ฐ๊ธฐ๋ ํ๊ณ ์ฐ๊ธฐํ ์ฌ๋๋ ๊ตฌํ๊ณ ์ด ๋ชจ๋ ๊ฒ์ ๋ค ํ ์๋ ์๊ฒ ์ฃ .
์ด์ ์ฝ๋๋ ๋ง์น ๋ก๋ฏธ์ค ์ญํ (์ธํฐํ์ด์ค)์ ํ๋ ๋ณ์ฐ์(๊ตฌํ์ฒด, ๋ฐฐ์ฐ)์ด ์ค๋ฆฌ์ฃ ์ญํ (์ธํฐํ์ด์ค)์ ํ๋ ์ฌ์ ์ฃผ์ธ๊ณต(๊ตฌํ์ฒด, ๋ฐฐ์ฐ)์ ์ง์ ์ด๋นํ๋ ๊ฒ๊ณผ ๊ฐ์ต๋๋ค.
๋ณ์ฐ์์ ๊ณต์ฐ๋ ํด์ผ ํ๊ณ ๋์์ ์ฌ์ ์ฃผ์ธ๊ณต๋ ๊ณต์ฐ์ ์ง์ ์ด๋นํด์ผ ํ๋ "๋ค์ํ ์ฑ ์"์ ๊ฐ๊ณ ์์ต๋๋ค.
private DiscountPolicy discountPolicy = new FixDiscountPolicy();
์ด ์ฝ๋๊ฐ ์ง์ ์ด๋นํ๋ ๊ฒ๊ณผ ๊ฐ์ ์์์ ๋๋ค.
์ด์ ์ฝ๋์ธ๋ฐ OrderServiceImpl์์๋ OrderService์ ๊ด๋ จ๋ ๋ก์ง๋ง ํด์ผํ๋๋ฐ, ์๊ฐ DiscountPolicy๋ FixDiscountPolicy๋ฅผ ํด์ผ ํ๋ค๊ณ ์ง์ ์ ํํ๋ ๋ฑ ๊ตฌ์ฒด์ ์ธ ๊ฒ๊น์ง ํ๊ณ ์์ต๋๋ค.
<๊ด์ฌ์ฌ๋ฅผ ๋ถ๋ฆฌ!!>
- ๋ฐฐ์ฐ๋ ๋ณธ์ธ์ ์ญํ ์ธ ๋ฐฐ์ญ์ ์ํํ๋ ๊ฒ์๋ง ์ง์คํด์ผ ํฉ๋๋ค.
- ๋ณ์ฐ์์ ์ด๋ ์ฌ์ ์ฃผ์ธ๊ณต์ด ์ ํ๋๋๋ผ๋ ๋๊ฐ์ด ๊ณต์ฐ์ ํ ์ ์์ด์ผ ํฉ๋๋ค.
- ๊ณต์ฐ์ ๊ตฌ์ฑํ๊ณ , ๋ด๋น ๋ฐฐ์ฐ๋ฅผ ์ญ์ธํ๊ณ , ์ญํ ์ ๋ง๋ ๋ฐฐ์ฐ๋ฅผ ์ง์ ํ๋ ์ฑ ์์ ๋ด๋นํ๋ ๋ณ๋์ "๊ณต์ฐ ๊ธฐํ์"๊ฐ ๋์ฌ ์์ ์ ๋๋ค.
- ๊ณต์ฐ ๊ธฐํ์๋ฅผ ๋ง๋ค๊ณ , ๋ฐฐ์ฐ์ ๊ณต์ฐ ๊ธฐํ์์ ์ฑ ์์ ํ์คํ ๋ถ๋ฆฌํด์ผ ํฉ๋๋ค.
3-2. AppConfig ๋ฑ์ฅ
์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ฒด ๋์ ๋ฐฉ์์ ๊ตฌ์ฑ(Config)ํ๊ธฐ ์ํด ๊ตฌํ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์ฐ๊ฒฐํ๋ ์ฑ ์์ ๊ฐ๋ ๋ณ๋์ ์ค์ ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
์์์ ์๊ธฐํ ๊ณต์ฐ ๊ธฐํ์ ๊ฐ์ ์ญํ ์ ๋๋ค.
ํ ๋ฒ ์ญํ ๋ง๋ค์ด๋ณด๊ณ ๋ฌธ์ ์ ์ ํด๊ฒฐํด๋ณด๊ฒ ์ต๋๋ค.
์ฐ์ ์ ์ฒด ๋์ ๋ฐฉ์์ ๊ตฌ์ฑํ๋ AppConfig๋ผ๋ ํด๋์ค๋ฅผ hello ํด๋ ์์ core ํจํค์ง ์์ ๋ง๋ค์ด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์ด์ hello ํด๋ ์์ core ํจํค์ง ์์ด๋ ๋ง์ hello.core๋ก ์ค์ฌ์ ์๊ธฐํ ๊ฒ์.
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl();
}
...
}
AppConfig๊ฐ ๋์ ์ ์ฒด์ ์ธ ์์ ์ ํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ์ด๋ ๊ฒ ๋ง๋ค์ด๋์ต๋๋ค.

๊ทธ๋ฆฌ๊ณ ์ผ๋จ MemberServiceImpl๋ก ๋์๊ฐ๋ณด๊ฒ ์ต๋๋ค.
private final MemberRepository memberRepository = new MemoryMemberRepository();
์ด ์ฝ๋๋ MemberServiceImpl์ด ๋๋ฌด ์ค์ง๋ผํผ...ใ
๊ทธ๋์ ์ ๋ค์ new MemoryMemberRepository()๋ ์ง์๋๋ค. AppConfig์์ ์ด๋ฐ๊ฑด ๋ค ํ ๊ฑฐ๋๊น์!
๊ทธ๋ฆฌ๊ณ MemberServiceImpl์ ์์ฑ์๋ฅผ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
์์ฑ์๋ฅผ ํตํด์ ์ด MemberRepository์ ๊ตฌํ์ฒด๊ฐ ๋ญ๊ฐ ๋ค์ด๊ฐ์ง๋ฅผ ์ ํํฉ๋๋ค.

๊ทธ๋ฆฌ๊ณ ์๊น ๋ง๋ค์๋ AppConfig ํด๋์ค๋ก ๋์๊ฐ๋๋ค.
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
์ฌ๊ธฐ์์ MemberServiceImpl์ MemoryMemberRepository๋ฅผ ํ ๋นํฉ๋๋ค.
์ด๋ ๊ฒ ๋๋ฉด ์ด๋ป๊ฒ ๋ ๊น์?
์ด๋์ ๊ฐ AppConfig๋ฅผ ํตํด์ memberService()๋ฅผ ๋ถ๋ฌ์ ์๋๋ค.
์ด๋ฌ๋ฉด MemberService ๊ตฌํ์ฒด ๊ฐ์ฒด(MemberServiceImpl)๊ฐ ์์ฑ๋๊ฒ ๋๋๋ฐ ๊ทธ ๋ MemoryMemberRepository๊ฐ
MemverServiceImpl์๋ MemoryMemberRepository์ ๋ํ ์ฝ๋๊ฐ ์๋์?
์๊ณ , ์ค๋ก์ง MemberRepository๋ผ๋ ์ธํฐํ์ด์ค๋ง ์์ต๋๋ค.
์ด๋ ๊ฒ ๋๋ฉด ์ด์ MemberServiceImpl์ ์ถ์ํ์๋ง ์์กดํ๊ฒ ๋๋ ๊ฒ์ ๋๋ค.
DIP๋ฅผ ์งํค๊ฒ ๋๋ ๊ฒ์ด๊ณ , ์ด์ MemberServiceImpl์ ๊ตฌ์ฒด์ ์ธ ์ํฉ์ ๋ชจ๋ฅด๊ฒ ๋๋ ๊ฒ์ ๋๋ค.
์ด๋ฐ ๊ฒ์ "์์ฑ์์ ์ฃผ์ "์ด๋ผ๊ณ ํฉ๋๋ค.

OrderService๋ ์์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ํด๋ณด๊ฒ ์ต๋๋ค.
AppConfig์์ ์์ ์ฒ๋ผ ์ด ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
public class AppConfig {
...
public OrderService orderService() {
return new OrderServiceImpl();
}
}
์์์ฒ๋ผ ๋๊ฐ์ด ์์ฑ์์ ์ฃผ์ ์ ํ ๊ฒ์ ๋๋ค.

OrderServiceImpl ํด๋์ค๋ก ๋์๊ฐ๋ณด๊ฒ ์ต๋๋ค.
private final MemberRepository memberRepository = new MemoryMemberRepository();
private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
์ฌ๊ธฐ์์ ์ฌ์ฉํ๋ ํ๋๊ฐ 2๊ฐ์์ต๋๋ค.
์์์ฒ๋ผ new ์ง์ ํ ๋น์ ๊ณผ๊ฐํ ์ง์ฐ๊ณ , ์์ฑ์๋ฅผ ์ถ๊ฐํด๋ณด๊ฒ ์ต๋๋ค.
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
...
}
final์ด ๋์ด์์ผ๋ฉด ์์ฑ์๋ฅผ ํตํด์ ํ ๋น์ด ๋์ด์ผ ํฉ๋๋ค.

๋ค์ AppConfig๋ก ๋์๊ฐ๋ณด๊ฒ ์ต๋๋ค.
public OrderService orderService() {
return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
}
์๊น์ฒ๋ผ AppConfig๊ฐ OrderServiceImpl์ MemoryMemberRepository์ FixDiscountPolicy๋ฅผ ์ง์ ํ ๋นํ๊ฒ ๋์์ต๋๋ค.
์ด๋ ๊ฒ ๋๋ฉด ์์์ฒ๋ผ DIP๋ฅผ ์ฒ ์ ํ๊ฒ ์งํค๊ฒ ๋ ๊ฒ์ ๋๋ค.
OrderServiceImpl ์ ์ฅ์์๋ discountPolicy์ FixDiscountPolicy๊ฐ ๋ค์ด์ฌ์ง RateDiscountPolicy๊ฐ ๋ค์ด์ฌ์ง ๋ชจ๋ฅด๊ฒ ๋ฉ๋๋ค. ์ธํฐํ์ด์ค์ธ OrderService์๋ง ์์กดํ๊ฒ ๋๋ ๊ฒ์ด์ฃ .

โ๏ธ๋งค์ฐ ์ค์ํ ๋ด์ฉ์ด๊ธฐ์ ๋ค์ ํ ๋ฒ ์ ๋ฆฌ๋ฅผ ํด๋ณด๊ฒ ์ต๋๋ค.โ๏ธ
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
}
}
<์ ๋ฆฌ1 - AppConfig>
1. AppConfig๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค์ ๋์์ ํ์ํ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ์์ฑํฉ๋๋ค.
- MemberServiceImpl
- MemoryMemberRepository
- OrderServiceImpl
- FixDiscountPolicy
2. AppConfig๋ ์์ฑํ ๊ฐ์ฒด ์ธ์คํด์ค์ ์ฐธ์กฐ(๋ ํผ๋ฐ์ค)๋ฅผ ์์ฑ์๋ฅผ ํตํด์ ์ฃผ์ (์ฐ๊ฒฐ)ํด์ค๋๋ค.
- MemberServiceImpl -> MemoryMemberRepository
- OrderServiceImpl -> MemoryMemberRepository, FixDiscountPolicy
์ฐธ๊ณ !!
์ง๊ธ์ ๊ฐ ํด๋์ค์ ์์ฑ์๊ฐ ์์ด์ ์ปดํ์ผ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค. ๋ฐ๋ก ๋ค์ ์ฝ๋์์ ์์ฑ์๋ฅผ ๋ง๋ค ์์ ์ ๋๋ค.
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Override
public void join(Member member) {
memberRepository.save(member);
}
@Override
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}
<์ ๋ฆฌ2 - MemberServiceImpl ์์ฑ์ ์ฃผ์ >
1. ์ค๊ณ ๋ณ๊ฒฝ์ผ๋ก MemberServiceImpl์ MemoryMemberRepository๋ฅผ ์์กดํ์ง ์์ต๋๋ค.
๋จ์ง MemberRepository ์ธํฐํ์ด์ค์๋ง ์์กดํฉ๋๋ค.
2. MemberServiceImpl ์ ์ฅ์์ ์์ฑ์๋ฅผ ํตํด ์ด๋ค ๊ตฌํ ๊ฐ์ฒด๊ฐ ๋ค์ด์ฌ์ง(์ฃผ์ ๋ ์ง)๋ ์ ์ ์์ต๋๋ค.
3. MemberServiceImpl์ ์์ฑ์๋ฅผ ํตํด์ ์ด๋ค ๊ตฌํ ๊ฐ์ฒด๋ฅผ ์ฃผ์ ํ ์ง๋ ์ค์ง ์ธ๋ถ(AppConfig)์์ ๊ฒฐ์ ๋ฉ๋๋ค.
4. MemberServiceImpl์ ์ด์ ๋ถํฐ ์์กด ๊ด๊ณ์ ๋ํ ๊ณ ๋ฏผ์ ์ธ๋ถ์ ๋งก๊ธฐ๊ณ ์คํ์๋ง ์ง์คํ๋ฉด ๋ฉ๋๋ค.
<์ ๋ฆฌ3 - ํ์ ํด๋์ค ๋ค์ด์ด๊ทธ๋จ>
1. ๊ฐ์ฒด์ ์์ฑ๊ณผ ์ฐ๊ฒฐ์ AppConfig๊ฐ ๋ด๋นํฉ๋๋ค.
2. DIP ์์ฑ: MemberServiceImpl์ MemberRepository์ธ ์ถ์์๋ง ์์กดํ๋ฉด ๋ฉ๋๋ค.
์ด์ ๊ตฌ์ฒด ํด๋์ค๋ ๋ชฐ๋ผ๋ ๋ฉ๋๋ค.
3. ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ: ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์ฐ๊ฒฐํ๋ ์ญํ ๊ณผ ์คํํ๋ ์ญํ ์ด ๋ช ํํ ๋ถ๋ฆฌ๋์์ต๋๋ค.
<์ ๋ฆฌ4 - ํ์ ๊ฐ์ฒด ์ธ์คํด์ค ๋ค์ด์ด๊ทธ๋จ>
1. appConfig ๊ฐ์ฒด๋ memoryMemberRepository ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ , ๊ทธ ์ฐธ์กฐ๊ฐ์ memberServiceImpl์ ์์ฑํ๋ฉด์ ์์ฑ์๋ก ์ ๋ฌํฉ๋๋ค.
2. ํด๋ผ์ด์ธํธ์ธ memberServiceImpl ์ ์ฅ์์ ๋ณด๋ฉด ์์กด ๊ด๊ณ๋ฅผ ๋ง์น ์ธ๋ถ์์ ์ฃผ์ ํด์ฃผ๋ ๊ฒ ๊ฐ๋ค๊ณ ํด์ DI(Dependency Injection) ์ฆ, ์์กด๊ด๊ณ ์ฃผ์ ๋๋ ์์กด์ฑ ์ฃผ์ ์ด๋ผ๊ณ ํฉ๋๋ค.
<์ ๋ฆฌ1 - OrderServiceImpl ์์ฑ์ ์ฃผ์ >
1. ์ค๊ณ ๋ณ๊ฒฝ์ผ๋ก OrderServiceImpl์ FixDiscountPolicy๋ฅผ ์์กดํ์ง ์์ต๋๋ค.
๋จ์ง DiscountPolicy ์ธํฐํ์ด์ค์๋ง ์์กดํฉ๋๋ค.
2. OrderServiceImpl ์ ์ฅ์์ ์์ฑ์๋ฅผ ํตํด ์ด๋ค ๊ตฌํ ๊ฐ์ฒด๊ฐ ๋ค์ด์ฌ์ง(์ฃผ์ ๋ ์ง)๋ ์ ์ ์์ต๋๋ค.
3. OrderServiceImpl์ ์์ฑ์๋ฅผ ํตํด์ ์ด๋ค ๊ตฌํ ๊ฐ์ฒด๋ฅผ ์ฃผ์ ํ ์ง๋ ์ค์ง ์ธ๋ถ(AppConfig)์์ ๊ฒฐ์ ํฉ๋๋ค.
4. OrderServiceImpl์ ์ด์ ๋ถํฐ ์คํ์๋ง ์ง์คํ๋ฉด ๋ฉ๋๋ค.
5. OrderServiceImpl์๋ MemoryMemberRepository, FixDiscountPolicy ๊ฐ์ฒด์ ์์กด ๊ด๊ณ๊ฐ ์ฃผ์ ๋ฉ๋๋ค.

AppConfig๋ฅผ ์คํํด๋ณด๊ฒ ์ต๋๋ค.
๊ธฐ์กด์ ๋ง๋ค์๋ MemberApp ํด๋์ค์ ๋ค์ด๊ฐ๋๋ค.
์ด์ AppConfig๊ฐ ์ ์ฒด์ ์ธ ๊ฒ์ ๊ด๋ฆฌํ๊ธฐ์ ๊ธฐ์กด์ MemberApp ํด๋์ค๋ ์์ ํด์ผ ํฉ๋๋ค.
public class MemberApp {
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
appConfig.memberService();
//MemberService memberService = new MemberServiceImpl();
MemberService memberService = appConfig.memberService();
...
}
}
AppConfig์์ MemberService์ ๊ตฌํ์ฒด๋ฅผ ํ ๋นํ๊ณ , MemberService๊ฐ ํ์ํ ์ธ์๋ฅผ ์ ๋ฃ์ด์คฌ๊ธฐ ๋๋ฌธ์ appConfig.memberService()๋ง ํธ์ถํด์ฃผ๋ฉด ๋ฉ๋๋ค.
๋ง์ฐฌ๊ฐ์ง๋ก OrderApp ํด๋์ค์ ๋ค์ด๊ฐ์ ์์ ํ๊ฒ ์ต๋๋ค.
public class OrderApp {
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
//MemberService memberService = new MemberServiceImpl();
//OrderService orderService = new OrderServiceImpl();
MemberService memberService = appConfig.memberService();
OrderService orderService = appConfig.orderService();
...
}
}
์์์ฒ๋ผ ์์ ์ ์๋ฃํ์์ต๋๋ค.
์คํํด๋ณผ๊ฒ์.
๋ ๋ค ์คํ์ ์ฑ๊ณตํ์์ต๋๋ค.
ํ ์คํธ ์ฝ๋๋ก๋ ์คํํด๋ณด๊ฒ ์ต๋๋ค.
๊ทธ์ ์ ํ ์คํธ ์ฝ๋๋ ์์ ํด์ผํฉ๋๋ค.
public class MemberServiceTest {
MemberService memberService;
//MemberService memberService = new MemberServiceImpl();
@BeforeEach
public void beforeEach() {
AppConfig appConfig = new AppConfig();
memberService = appConfig.memberService();
}
@Test
void join() {
...
}
}
MemberServiceTest ์ฝ๋ ์์ ์๋ฃํ์ต๋๋ค.
@BeforeEach์ ๊ดํ ์ค๋ช ์ ๋ฐ๋ก ๋ฐ์ ๋์ต๋๋ค.
public class OrderServiceTest {
MemberService memberService;
OrderService orderService;
//MemberService memberService = new MemberServiceImpl();
//OrderService orderService = new OrderServiceImpl();
@BeforeEach
public void beforeEach() {
AppConfig appConfig = new AppConfig();
memberService = appConfig.memberService();
orderService = appConfig.orderService();
}
@Test
void createOrder() {
...
}
}
@BeforeEach๋..
ํ ์คํธ ์คํํ๊ธฐ ์ ์ ๋ฌด์กฐ๊ฑด ์คํ๋๋ ๊ฒ์ ๋๋ค.
OrderServiceTest๊น์ง ์์ ์๋ฃํ๊ณ , ํ ์คํธ ์ฝ๋๋ฅผ ์คํํด๋ณด๊ฒ ์ต๋๋ค.
๋ ๋ค ์คํ ์ฑ๊ณตํ์์ต๋๋ค.

3-3. AppConfig ๋ฆฌํฉํฐ๋ง
ํ์ฌ AppConfig๋ฅผ ๋ณด๋ฉด ์ค๋ณต์ด ์๊ณ , ์ญํ ์ ๋ฐ๋ฅธ ๊ตฌํ์ด ์ ๋ณด์ด์ง ์์ต๋๋ค.๐ญ
๊ธฐ๋ํ๋ ๊ทธ๋ฆผ์ ๋ถ๋ช ์ด๋ฌ๊ฑฐ๋ ์.
์ง๊ธ AppConfig์๋ ์ญํ , ๊ตฌํ ์ด๋ฐ๊ฒ ํ ๋์ ์ ๋ณด์ด์ง ์์ต๋๋ค.
AppConfig ํด๋์ค๋ก ๊ฐ๋ณด๊ฒ ์ต๋๋ค.
new MemoryMemberRepository() ์ฝ๋๋ฅผ ์ ํํ ํ Window ๊ธฐ์ค ctrl + Alt + M์ ๋๋ฌ์ค๋๋ค.
(MAC์ Command + Option + M)
์ถ์ฒํ๋ ์ด๋ฆ๋ง๊ณ ์ ๊ฐ ์ํ๋ ์ด๋ฆ์ ์ฌ์ฉํ๊ธฐ ์ํด ์์ ์ต์ ๋ฒํผโ๏ธ์ ๋๋ฆ ๋๋ค.
๊ธฐํ ์ต์ ์ ๋๋ฅธ ํ, ์ด๋ฆ์ memberRepository๋ก ํ๊ณ , ๋ฐํ ํ์ ์ ๊ตฌ์ฒด ํด๋์ค๊ฐ ์๋ ์ธํฐํ์ด์ค์ธ MemberRepository๋ก ํด๋ณด๊ฒ ์ต๋๋ค.
static ์คํ์ ๋๋ฅด์๋ฉด ์ ๋ฉ๋๋ค.
๊ทธ๋ฌ๊ณ ๋ฆฌํฉํฐ๋ง์ ๋๋ฅด๋ฉด ์ค๋ณตํ๋๊ฒ ์๋ค๊ณ ๋น๋๋ค.
๊ทธ๋ผ ๊ฐ๋ณ๊ฒ ๋์ฒดํ๋ค๊ณ ๋๋ฅด๋ฉด ๋ฉ๋๋ค.
FixDiscountPolicy๋ ์์ ๋ฐฉ๋ฒ์ฒ๋ผ ํด๋ณด๊ฒ ์ต๋๋ค.
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
private MemberRepository memberRepository() {
return new MemoryMemberRepository();
} //์๋ก ์๊ธด ๋ถ๋ถ
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
private DiscountPolicy discountPolicy() {
return new FixDiscountPolicy();
} //์๋ก ์๊ธด ๋ถ๋ถ
}
ํด๋ณด๋ฉด ๊ธฐ์กด์ new MemoryMemberRepository์ new FixDiscountPolicy๊ฐ memberRepository()์ discountPolicy()๋ก ๋ฐ๋์๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
์ด๋ ๊ฒ ๋ฆฌํฉํ ๋ง์ ํด ๋์ผ๋ฉด ์ญํ ๊ณผ ๊ตฌํ์ด ์ ๋๋ฌ๋๊ฒ ๋ฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ , ๋์ค์ ์์ ์ ํด์ผ ํ๋ฉด ์ด ์ฝ๋๋ง ์์ ํ๋ฉด ๋ฉ๋๋ค.

4. ์๋ก์ด ๊ตฌ์กฐ์ ํ ์ธ ์ ์ฑ ์ ์ฉ - ์ ๋ฅ ํ ์ธ ์ ์ฑ ์ผ๋ก ๋ณ๊ฒฝ
์ฒ์์ผ๋ฌ ๋์๊ฐ์ ์ ์ก ํ ์ธ ์ ์ฑ ์ ์ ๋ฅ ํ ์ธ ์ ์ฑ ์ผ๋ก ๋ณ๊ฒฝํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
FixdiscountPolicy๋ฅผ RateDiscountPolicy๋ก ๋ฐ๊พธ๋ ๊ฒ์ ๋๋ค.
์ด๋ค ๋ถ๋ถ๋ง ๋ณ๊ฒฝํ๋ฉด ๋ ๊น์?
AppConfig๋ง ๋ณ๊ฒฝํ๋ฉด ๋ฉ๋๋ค!!!
AppConfig์ ๋ฑ์ฅ์ผ๋ก ๋ฐ์ ๊ทธ๋ฆผ์ฒ๋ผ ์ ํ๋ฆฌ์ผ์ด์ ์ด ํฌ๊ฒ ์ฌ์ฉ ์์ญ๊ณผ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ตฌ์ฑํ๋ ์์ญ์ผ๋ก ๋ถ๋ฆฌ๋์์ต๋๋ค.
์ฌ๊ธฐ์์ FixDiscountPolicy๋ฅผ ๋ณ๊ฒฝํ๊ณ ์ถ์ผ๋ฉด...
๋ฐ์ ์ฌ์ง์ฒ๋ผ ํ๋ฉด ๋๊ฒ ์ฃ .
๊ตฌ์ฑ ์์ญ์ ์ฝ๋๋ง ์์ ๋๋ฉด ๋๊ณ , ์ฌ์ฉ ์์ญ์ ์ฝ๋๋ ์์ ์ ๋๋ ๋๊ฒ ์ฃ .
๊ตฌ์ฑ ์์ญ์ธ AppConfig์ ์ฝ๋๋ฅผ ํ ๋ฒ ์์ ํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
public class AppConfig {
...
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
//์ฌ๊ธธ ๋ณ๊ฒฝ
private DiscountPolicy discountPolicy() {
return new FixDiscountPolicy();
}
}
์๋ ๊ธฐ์กด ์ ์ก ํ ์ธ ์ ์ฑ ์ ์ฌ์ฉํ ๋๋ ์ฝ๋๊ฐ ์ด๋ฌ์ต๋๋ค.
์ ๋ฅ ํ ์ธ ์ ์ฑ ์ผ๋ก ๋ณ๊ฒฝ์ ํ๋ ค๋ฉด ๊ฐ๋จํฉ๋๋ค.
private DiscountPolicy discountPolicy() {
//return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
FixDiscountPolicy๋ฅผ ๋ฆฌํดํ๊ณ ์๋ ๊ฒ์ RateDiscountPolicy๋ฅผ ๋ฆฌํดํ๋๋ก ๋ณ๊ฒฝํ๋ฉด ๋ฉ๋๋ค.
ํ ์คํธ๋ฅผ ํด๋ณด๊ฒ ์ต๋๋ค.
ํ ์คํธ๊ฐ ์ ๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ ๋ฆฌ๋ฅผ ํด๋ณด์๋ฉด...
- AppConfig์์ ํ ์ธ ์ ์ฑ ์ญํ ์ ๋ด๋นํ๋ ๊ตฌํ์ FixDiscountPolicy์์ RateDiscountPolicy๋ก ๋ณ๊ฒฝํ์ต๋๋ค.
- ์ด์ ํ ์ธ ์ ์ฑ
์ ๋ณ๊ฒฝํด๋ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ฑ ์ญํ ์ ๋ด๋นํ๋ AppConfig๋ง ๋ณ๊ฒฝํ๋ฉด ๋ฉ๋๋ค.
- ํด๋ผ์ด์ธํธ ์ฝ๋์ธ OrderServiceImpl๋ฅผ ํฌํจํด์ ์ฌ์ฉ ์์ญ์ ์ด๋ค ์ฝ๋๋ ๋ณ๊ฒฝํ ํ์๊ฐ ์์ต๋๋ค.
- ๊ตฌ์ฑ ์์ญ์ ๋น์ฐํ ๋ณ๊ฒฝ๋ฉ๋๋ค.
๊ตฌ์ฑ ์ญํ ์ ๋ด๋นํ๋ AppConfig๋ฅผ ์ ํ๋ฆฌ์ผ์ด์ ์ด๋ผ๋ ๊ณต์ฐ์ ๊ธฐํ์๋ก ์๊ฐํด๋ณด๊ฒ ์ต๋๋ค.
๊ณต์ฐ ๊ธฐํ์๋ ๊ณต์ฐ ์ฐธ์ฌ์์ธ ๊ตฌํ ๊ฐ์ฒด๋ค์ ๋ชจ๋ ์์์ผ ํฉ๋๋ค.

5. ์ข์ ๊ฐ์ฒด ์งํฅ ์ค๊ณ์ 5๊ฐ์ง ์์น์ ์ ์ฉ
์ฌ๊ธฐ์๋ ํฌ๊ฒ SRP, DIP, OCP ์ด๋ ๊ฒ 3๊ฐ์ง๊ฐ ์ ์ฉ๋์์ต๋๋ค.
5-1. SRP ๋จ์ผ ์ฑ ์ ์์น
ํ ํด๋์ค๋ ํ๋์ ์ฑ ์๋ง ๊ฐ์ ธ์ผ ํ๋ค.
- ํด๋ผ์ด์ธํธ ๊ฐ์ฒด๋ ์ง์ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์ฐ๊ฒฐํ๊ณ ์คํํ๋ ๋ค์ํ ์ฑ ์์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
- SRP ๋จ์ผ ์ฑ
์ ์์น์ ๋ฐ๋ฅด๋ฉด์ ๊ด์ฌ์ฌ๋ฅผ ๋ถ๋ฆฌํ์ต๋๋ค.
- AppConfig: ๊ตฌํ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์ฐ๊ฒฐํ๋ ์ฑ ์ ๋ด๋น
- ํด๋ผ์ด์ธํธ ๊ฐ์ฒด: ์คํํ๋ ์ฑ ์ ๋ด๋น
5-2. DIP ์์กด ๊ด๊ณ ์ญ์ ์์น
ํ๋ก๊ทธ๋๋จธ๋ ์ถ์ํ์ ์์กดํด์ผํ๊ณ , ๊ตฌ์ฒดํ์ ์์กดํ๋ฉด ์ ๋๋ค.
์์กด์ฑ ์ฃผ์ ์ ์ด ์์น์ ๋ฐ๋ฅด๋ ๋ฐฉ๋ฒ ์ค ํ๋๋ค.
- ์๋ก์ด ํ ์ธ ์ ์ฑ
์ ๊ฐ๋ฐํ๊ณ , ์ ์ฉํ๋ ค๊ณ ํ๋ ํด๋ผ์ด์ธํธ ์ฝ๋๋ ํจ๊ป ๋ณ๊ฒฝํด์ผ ํ์ต๋๋ค.
- ์๋ํ๋ฉด, ๊ธฐ์กด ํด๋ผ์ด์ธํธ ์ฝ๋ OrderServiceImpl๋ DIP๋ฅผ ์งํค๋ฉฐ DiscountPolicy ์ถ์ํ ์ธํฐํ์ด์ค์ ์์กดํ๋ ๊ฒ ๊ฐ์์ง๋ง, FixDiscountPolicy ๊ตฌ์ฒดํ ๊ตฌํ ํด๋์ค์๋ ํจ๊ป ์์กดํ์ต๋๋ค.
- ํด๋ผ์ด์ธํธ ์ฝ๋๊ฐ DiscountPolicy ์ถ์ํ ์ธํฐํ์ด์ค์๋ง ์์กดํ๋๋ก ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ์ต๋๋ค.
- ํ์ง๋ง... ํด๋ผ์ด์ธํธ ์ฝ๋๋ ์ธํฐํ์ด์ค๋ง์ผ๋ก๋ ์๋ฌด ๊ฒ๋ ์คํํ ์ ์์์ต๋๋ค.
- AppConfig๊ฐ FixDiscountPolicy ๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ํด๋ผ์ด์ธํธ ์ฝ๋ ๋์ ์์ฑํด์ ํด๋ผ์ด์ธํธ ์ฝ๋์ ์์กด ๊ด๊ณ๋ฅผ ์ฃผ์
ํ์ต๋๋ค.
์ด๋ ๊ฒ ํด์ DIP ์์น์ ๋ฐ๋ฅด๋ฉด์ ๋ฌธ์ ๋ ํด๊ฒฐํ์ต๋๋ค.
5-3. OCP
์ํํธ์จ์ด ์์๋ ํ์ฅ์๋ ์ด๋ ค ์์ผ๋ ๋ณ๊ฒฝ์๋ ๋ซํ ์์ด์ผ ํ๋ค.
- ๋คํ์ฑ์ ์ฌ์ฉํ๊ณ , ํด๋ผ์ด์ธํธ๊ฐ DIP๋ฅผ ์ง์ผฐ์ต๋๋ค.
- ์ ํ๋ฆฌ์ผ์ด์
์ ์ฌ์ฉ ์์ญ๊ณผ ๊ตฌ์ฑ ์์ญ์ผ๋ก ๋๋ด์ต๋๋ค.
- AppConfig๊ฐ ์์กด ๊ด๊ณ๋ฅผ FixDiscountPolicy์์ RateDiscountPolicy๋ก ๋ณ๊ฒฝํด์ ํด๋ผ์ด์ธํธ ์ฝ๋์ ์ฃผ์ ํ๋ฏ๋ก ํด๋ผ์ด์ธํธ ์ฝ๋๋ ๋ณ๊ฒฝํ์ง ์์๋ ๋ฉ๋๋ค.
- ์ํํธ์จ์ด ์์๋ฅผ ์๋กญ๊ฒ ํ์ฅํด๋ ์ฌ์ฉ ์์ญ์ ๋ณ๊ฒฝ์ ๋ซํ์์ต๋๋ค.

6. IoC, DI, ๊ทธ๋ฆฌ๊ณ ์ปจํ ์ด๋
6-1. ์ ์ด์ ์ญ์ IoC (Inversion of Control)
- AppConfig๊ฐ ๋ฑ์ฅํ๊ธฐ ์ ...
- ๊ธฐ์กด ํ๋ก๊ทธ๋จ์ ํด๋ผ์ด์ธํธ ๊ตฌํ ๊ฐ์ฒด๊ฐ ์ค์ค๋ก ํ์ํ ์๋ฒ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์ฐ๊ฒฐํ๊ณ ์คํํฉ๋๋ค.
ํ ๋ง๋๋ก, ๊ตฌํ ๊ฐ์ฒด๊ฐ ํ๋ก๊ทธ๋จ์ ์ ์ด ํ๋ฆ์ ์ค์ค๋ก ์กฐ์ข ํ๋ค๊ณ ์ ์ํ ์ ์์ต๋๋ค. ๊ฐ๋ฐ์ ์ ์ฅ์์๋ ์์ฐ์ค๋ฌ์ด ํ๋ฆ์ด์ฃ .
- ๊ธฐ์กด ํ๋ก๊ทธ๋จ์ ํด๋ผ์ด์ธํธ ๊ตฌํ ๊ฐ์ฒด๊ฐ ์ค์ค๋ก ํ์ํ ์๋ฒ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์ฐ๊ฒฐํ๊ณ ์คํํฉ๋๋ค.
- AppConfig๊ฐ ๋ฑ์ฅํ ์ดํ...
- ๊ตฌํ ๊ฐ์ฒด๋ ์์ ์ ๋ก์ง์ ์คํํ๋ ์ญํ ๋ง ๋ด๋นํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ , ํ๋ก๊ทธ๋จ์ ์ ์ด ํ๋ฆ์ ์ด์ AppConfig๊ฐ ๊ฐ์ ธ๊ฐ๋๋ค.
- ex) OrderServiceImpl์ ํ์ํ ์ธํฐํ์ด์ค๋ค์ ํธ์ถํ์ง๋ง, ์ด๋ค ๊ตฌํ ๊ฐ์ฒด๋ค์ด ์คํ๋ ์ง ๋ชจ๋ฆ ๋๋ค. - ํ๋ก๊ทธ๋จ์ ์ ์ด ํ๋ฆ์ ๋ํ ๊ถํ์ ๋ชจ๋ AppConfig๊ฐ ๊ฐ์ง๊ณ ์์ต๋๋ค.
์ฌ์ง์ด OrderServiceImpl๋ AppConfig๊ฐ ์์ฑํฉ๋๋ค. - ๊ทธ๋ฆฌ๊ณ , AppConfig๋ OrderServiceImpl์ด ์๋ OrderService ์ธํฐํ์ด์ค์ ๋ค๋ฅธ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์คํํ ์๋ ์์ต๋๋ค.
OrderServiceImpl์ ๊ทธ๋ฐ ์ฌ์ค๋ ๋ชจ๋ฅธ ์ฑ ๋ฌต๋ฌตํ ์์ ์ ๋ก์ง์ ์คํํ ๋ฟ...
- ๊ตฌํ ๊ฐ์ฒด๋ ์์ ์ ๋ก์ง์ ์คํํ๋ ์ญํ ๋ง ๋ด๋นํฉ๋๋ค.
- ์ด๋ ๋ฏ ํ๋ก๊ทธ๋จ์ ์ ์ด ํ๋ฆ์ ์ง์ ์ ์ดํ๋ ๊ฒ์ด ์๋๋ผ ์ธ๋ถ์์ ๊ด๋ฆฌํ๋ ๊ฒ์ ์ ์ด์ ์ญ์ (IoC)์ด๋ผ๊ณ ํฉ๋๋ค.
ํ๋ ์์ํฌ๊ฐ ๋ด๊ฐ ์์ฑํ ์ฝ๋๋ฅผ ์ ์ดํ๊ณ , ๋์ ์คํํ๋ฉด ๊ทธ๊ฒ์ ํ๋ ์์ํฌ๊ฐ ๋ง์ต๋๋ค. (JUnit)
๋ฐ๋ฉด์, ๋ด๊ฐ ์์ฑํ ์ฝ๋๊ฐ ์ง์ ์ ์ด์ ํ๋ฆ์ ๋ด๋นํ๋ค๋ฉด ๊ทธ๊ฒ์ ํ๋ ์์ํฌ๊ฐ ์๋๋ผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
6-2. ์์กด๊ด๊ณ ์ฃผ์ DI (Dependency Injection)
OrderServiceImpl์ DiscountPolicy ์ธํฐํ์ด์ค์ ์์กดํฉ๋๋ค.
๊ทธ๋์ ์ค์ ์ด๋ค ๊ตฌํ ๊ฐ์ฒด๊ฐ ์ฌ์ฉ๋ ์ง๋ ๋ชจ๋ฆ ๋๋ค.
์์กด๊ด๊ณ๋ ์ ์ ์ธ ํด๋์ค ์์กด๊ด๊ณ์ ์คํ ์์ ์ ๊ฒฐ์ ๋๋ ๋์ ์ธ ๊ฐ์ฒด(์ธ์คํด์ค) ์์กด๊ด๊ณ๋ค์ ๋ถ๋ฆฌํด์ ์๊ฐํด์ผ ํฉ๋๋ค.
- ์ ์ ์ธ ํด๋์ค ์์กด๊ด๊ณ
ํด๋์ค๊ฐ ์ฌ์ฉํ๋ import ์ฝ๋๋ง ๋ณด๊ณ ์์กด๊ด๊ณ๋ฅผ ์ฝ๊ฒ ํ๋จํ ์ ์์ต๋๋ค.
์ ์ ์ธ ์์กด๊ด๊ณ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํํ์ง ์์๋ ๋ถ์ํ ์ ์์ต๋๋ค.
๋ฐ์ ํด๋์ค ๋ค์ด์ด๊ทธ๋จ์ ๋ณด๋ฉด OrderServiceImpl์ MemberRepository, DiscountPolicy์ ์์กดํ๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
๊ทธ๋ฐ๋ฐ ์ด๋ฌํ ํด๋์ค ์์กด๊ด๊ณ ๋ง์ผ๋ก๋ ์ค์ ์ด๋ค ๊ฐ์ฒด๊ฐ OrderServiceImpl์ ์ฃผ์ ๋ ์ง ์ ์ ์์ต๋๋ค.
- ๋์ ์ธ ๊ฐ์ฒด ์ธ์คํด์ค ์์กด๊ด๊ณ
์ ํ๋ฆฌ์ผ์ด์ ์คํ ์์ ์ ์ค์ ์์ฑ๋ ๊ฐ์ฒด ์ธ์คํด์ค์ ์ฐธ์กฐ๊ฐ ์ฐ๊ฒฐ๋ ์์กด๊ด๊ณ ์ ๋๋ค.
๋ฐ์ ๊ฐ์ฒด ๋ค์ด์ด๊ทธ๋จ์ ํ ๋ฒ ๋ด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์ ํ๋ฆฌ์ผ์ด์ ์คํ ์์ (๋ฐํ์)์ ์ธ๋ถ์์ ์ค์ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ํด๋ผ์ด์ธํธ์ ์ ๋ฌํด์ ํด๋ผ์ด์ธํธ์ ์๋ฒ์ ์ค์ ์์กด๊ด๊ณ๊ฐ ์ฐ๊ฒฐ๋๋ ๊ฒ์ ์์กด๊ด๊ณ ์ฃผ์ ์ด๋ผ๊ณ ํฉ๋๋ค.
๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ณ , ๊ทธ ์ฐธ์กฐ๊ฐ์ ์ ๋ฌํด์ ์ฐ๊ฒฐ๋ฉ๋๋ค.
์์กด๊ด๊ณ ์ฃผ์ ์ ์ฌ์ฉํ๋ฉด ํด๋ผ์ด์ธํธ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ ํด๋ผ์ด์ธํธ๊ฐ ํธ์ถํ๋ ๋์์ ํ์ ์ธ์คํด์ค๋ฅผ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
โญ๊ทธ๋ฆฌ๊ณ , ์์กด๊ด๊ณ ์ฃผ์ ์ ์ฌ์ฉํ๋ฉด ์ ์ ์ธ ํด๋์ค ์์กด๊ด๊ณ๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ , ๋์ ์ธ ๊ฐ์ฒด ์ธ์คํด์ค ์์กด๊ด๊ณ๋ฅผ ์ฝ๊ฒ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
6-3. IoC ์ปจํ ์ด๋, DI ์ปจํ ์ด๋
AppConfig์ฒ๋ผ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ด๋ฆฌํ๋ฉด์ ์์กด๊ด๊ณ๋ฅผ ์ฐ๊ฒฐํด์ฃผ๋ ๊ฒ์ IoC ์ปจํ ์ด๋ ๋๋ DI ์ปจํ ์ด๋๋ผ๊ณ ํฉ๋๋ค.
๊ทธ๋ฐ๋ฐ, ์์กด๊ด๊ณ ์ฃผ์ ์ ์ด์ ์ ๋ง์ถ์ด ์ต๊ทผ์๋ ์ฃผ๋ก DI ์ปจํ ์ด๋๋ผ๊ณ ํฉ๋๋ค.
(์ด์๋ธ๋ฌ, ์ค๋ธ์ ํธ ํฉํ ๋ฆฌ ๋ฑ์ผ๋ก ๋ถ๋ฆฌ๊ธฐ๋ ํฉ๋๋ค.)

7. ์คํ๋ง์ผ๋ก ์ ํํ๊ธฐ
์ง๊ธ๊น์ง๋ ์คํ๋ง ์์ด ์์ํ ์๋ฐ ์ฝ๋๋ก๋ง ์์ฑํ์ต๋๋ค.
์ด์ ๋๋์ด ์คํ๋ง์ ์ฌ์ฉํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์ฐ์ AppConfig๋ฅผ ์คํ๋ง ๊ธฐ๋ฐ์ผ๋ก ๋ฐ๊ฟ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
@Configuration
//์ค์ ์ ๋ณด, ๊ตฌ์ฑ ์ ๋ณด
public class AppConfig {
@Bean
//๊ฐ ๋ฉ์๋๋ง๋ค @Bean ์ ์ด์ค
//์ด๋ ๊ฒ ํ๋ฉด ์คํ๋ง ์ปจํ
์ด๋์ ์ ์ฉ๋จ
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public DiscountPolicy discountPolicy() {
return new RateDiscountPolicy();
}
}
AppConfig ํจ์ ์์ @Configuration์ด๋ผ๋ annotation์ ๋ฌ์์ต๋๋ค.
@Configuration์ด๋ ๋ญ๊น์?
ํ ๋ง๋๋ก ์ค์ ์ ๋ณด, ๊ตฌ์ฑ ์ ๋ณด๋ฅผ ๋ปํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ , ๊ฐ ๋ฉ์๋๋ง๋ค @Bean์ ๋ถํ์ค๋๋ค.
์ด๋ ๊ฒ ๋ถํ์ฃผ๋ฉด ์คํ๋ง ์ปจํ ์ด๋์ ์ ์ฉ์ด ๋ฉ๋๋ค.
์ด์ MemberApp ํด๋์ค๋ก ์ด๋ํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
public class MemberApp {
public static void main(String[] args) {
//AppConfig appConfig = new AppConfig();
//MemberService memberService = appConfig.memberService();
//์คํ๋ง์ ApplicationContext๋ก ์์
//์ด๊ฒ ์คํ๋ง ์ปจํ
์ด๋๋ผ๊ณ ๋ณด๋ฉด ๋จ.
//@Bean์ ๋ค ๊ด๋ฆฌํด์ค
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
//์ ๋ฌธ์ฅ: AppConfig์ ์๋ ํ๊ฒฝ ์ค์ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ @Bean์ ์คํ๋ง ์ปจํ
์ด๋์ ๋ฃ์ด์ ๋ค ๊ด๋ฆฌํด์ค
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
Member member = new Member(1L, "์์", Grade.VIP);
memberService.join(member);
Member findMember = memberService.findMember(1L);
System.out.println("new member = " + member.getName());
System.out.println("findMember = " + findMember.getName());
}
}
๋ฐ๋ ๋ถ๋ถ์ด ๋ณด์ด์๋์?
์คํ๋ง์ ApplicationContext๋ก ์์ํฉ๋๋ค. ์ด๊ฒ์ ์คํ๋ง ์ปจํ ์ด๋๋ผ๊ณ ๋ณด๋ฉด ๋ผ์.
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); ๋ฌธ์ฅ์ ํด์ํด๋ณด๊ฒ ์ต๋๋ค.
=> AppConfig์ ์๋ ํ๊ฒฝ ์ค์ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ @Bean์ ์คํ๋ง ์ปจํ ์ด๋์ ๋ฃ์ด์ ๋ค ๊ด๋ฆฌ๋ฅผ ํด์ค๋ค๋ ๋ป์ ๋๋ค.
OrderApp ํด๋์ค๋ก ์ด๋ํด๋ณด๊ฒ ์ต๋๋ค.
public class OrderApp {
public static void main(String[] args) {
//AppConfig appConfig = new AppConfig();
//MemberService memberService = appConfig.memberService();
//OrderService orderService = appConfig.orderService();
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, "์์", Grade.VIP);
memberService.join(member);
Order order = orderService.createOrder(memberId, "์ด์ฝ๋ฆฟ", 20000);
System.out.println("order = " + order);
}
}
๋ ์ฝ๋๋ฅผ ์คํํ๋ฉด ์คํ๋ง ๊ด๋ จ ๋ก๊ทธ๊ฐ ๋ช ์ค ์คํ๋๋ฉด์ ๊ธฐ์กด๊ณผ ๋์ผํ ๊ฒฐ๊ณผ๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค.
- ์คํ๋ง ์ปจํ ์ด๋
- ApplicationContext๋ฅผ ์คํ๋ง ์ปจํ ์ด๋๋ผ๊ณ ํฉ๋๋ค.
- ๊ธฐ์กด์๋ ๊ฐ๋ฐ์๊ฐ AppConfig๋ฅผ ์ฌ์ฉํด์ ์ง์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ DI๋ฅผ ํ์ง๋ง, ์ด์ ๋ถํฐ๋ ์คํ๋ง ์ปจํ ์ด๋๋ฅผ ํตํด์ ์ฌ์ฉํฉ๋๋ค.
- ์คํ๋ง ์ปจํ ์ด๋๋ @Configuration์ด ๋ถ์ AppConfig๋ฅผ ์ค์ (๊ตฌ์ฑ) ์ ๋ณด๋ก ์ฌ์ฉํฉ๋๋ค.
์ฌ๊ธฐ์ @Bean์ด๋ผ๊ณ ์ ํ ๋ฉ์๋๋ฅผ ๋ชจ๋ ํธ์ถํด์ ๋ฐํ๋ ๊ฐ์ฒด๋ฅผ ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋กํฉ๋๋ค.
์ด๋ ๊ฒ ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋ก๋ ๊ฐ์ฒด๋ฅผ ์คํ๋ง ๋น์ด๋ผ๊ณ ํฉ๋๋ค.
- ์คํ๋ง ๋น์ @Bean์ด ๋ถ์ ๋ฉ์๋์ ๋ช ์ ์คํ๋ง ๋น์ ์ด๋ฆ์ผ๋ก ์ฌ์ฉํฉ๋๋ค. (memberService, OrderService)
- ์ด์ ์๋ ๊ฐ๋ฐ์๊ฐ ํ์ํ ๊ฐ์ฒด๋ฅผ AppConfig๋ฅผ ์ฌ์ฉํด์ ์ง์ ์กฐํํ์ง๋ง, ์ด์ ๋ถํฐ๋ ์คํ๋ง ์ปจํ ์ด๋๋ฅผ ํตํด์ ํ์ํ ์คํ๋ง ๋น(๊ฐ์ฒด)๋ฅผ ์ฐพ์์ผ ํฉ๋๋ค.
โญ์คํ๋ง ๋น์ applicationContext.getBean() ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ ์ฐพ์ ์ ์์ต๋๋ค.
- ๊ธฐ์กด์๋ ๊ฐ๋ฐ์๊ฐ ์ง์ ์๋ฐ ์ฝ๋๋ก ๋ชจ๋ ๊ฒ์ ํ๋ค๋ฉด ์ด์ ๋ถํฐ๋ ์คํ๋ง ์ปจํ ์ด๋์ ๊ฐ์ฒด๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๊ณ , ์คํ๋ง ์ปจํ ์ด๋์์ ์คํ๋ง ๋น์ ์ฐพ์์ ์ฌ์ฉํ๋๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค.
Q. ์ฝ๋๊ฐ ์ฝ๊ฐ ๋ ๋ณต์กํด์ง ๊ฒ ๊ฐ์๋ฐ ์คํ๋ง ์ปจํ ์ด๋๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ค ์ฅ์ ์ด ์์๊น์?
A. ์ด๋ง์ด๋งํ ์ฅ์ ์ด ์์ต๋๋ค. ์ฝ๋๊ฐ ์ง๊ธ์ ๋จ์ํ์ง๋ง ๋์ค์ ๋ณต์กํด์ง๋ฉด ๊ฐ๋ฐํ๊ธฐ๊ฐ ํ๋ค์ด์ง๋๋ค. ์คํ๋ง ์ปจํ ์ด๋๊ฐ ๊ด๋ฆฌํด์ค์ผ๋ก์จ ํด์ค ์ ์๋ ๊ธฐ๋ฅ์ด ์ด๋ง์ด๋งํฉ๋๋ค.
์น์ 3๋ ๋์ด ๋ฌ์ต๋๋ค.
๋๋์ด ์คํ๋ง์ ์ฒซ ๊ฑธ์์ ํ๋ค์.
์ด์ ๋ถํฐ ๋ณธ๊ฒฉ์ ์ผ๋ก ์คํ๋ง ๋น๊ณผ ์คํ๋ง ์ปจํ ์ด๋๋ฅผ ์์๋ณผ๊ฑฐ์์!
๊ทธ๋ผ ์๋ ~~
