[๊ฐ์] ์คํ๋ง ํต์ฌ ์๋ฆฌ- ๊ธฐ๋ณธํธ 2
์คํ๋ง ํต์ฌ ์๋ฆฌ - ๊ธฐ๋ณธํธ - ์ธํ๋ฐ | ๊ฐ์
์คํ๋ง ์ ๋ฌธ์๊ฐ ์์ ๋ฅผ ๋ง๋ค์ด๊ฐ๋ฉด์ ์คํ๋ง์ ํต์ฌ ์๋ฆฌ๋ฅผ ์ดํดํ๊ณ , ์คํ๋ง ๊ธฐ๋ณธ๊ธฐ๋ฅผ ํ์คํ ๋ค์ง ์ ์์ต๋๋ค., ์คํ๋ง ํต์ฌ ์๋ฆฌ๋ฅผ ์ดํดํ๊ณ , ์ฑ์ฅํ๋ ๊ฐ๋ฐ์๊ฐ ๋์ด๋ณด์ธ์! ๐ฃ ํ์ธํด์ฃผ
www.inflearn.com
์ถ์ฒ: ๊น์ํ ๊ฐ์ฌ๋ ์คํ๋ง ํต์ฌ ์๋ฆฌ- ๊ธฐ๋ณธํธ
3. ์คํ๋ง ํต์ฌ ์๋ฆฌ ์ดํด1 - ๊ฐ์ฒด ์งํฅ ์๋ฆฌ ์ ์ฉ
- ์๋ก์ด ํ ์ธ ์ ์ฑ ๊ฐ๋ฐ
์ ๋ฒ์ ๊ณ ์ ๊ธ์ก ํ ์ธ์ ๋ง๋ค์์ผ๋ ์ด๋ฒ์ ์ ๋ฅ ๊ธ์ก ํ ์ธ ํด๋์ค RateDiscountPolicy๋ฅผ ๊ตฌํํด ๋ณด์๋ค.
ํ ์คํธ์ฝ๋
//RateDiscountPolicyTest.java
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
assertThat(discount).isEqualTo(1000);
}
@Test
@DisplayName("VIP๊ฐ ์๋๋ฉด ํ ์ธ์ด ์ ์ฉ๋์ง ์์์ผ ํ๋ค.")
void vip_x(){
//given
Member member = new Member(1L, "memberVIP", Grade.BASIC);
//when
int discount = discountPolicy.discount(member, 10000);
//then
assertThat(discount).isEqualTo(1000); // ์ค๋ฅ๋์ผํ๋ค. ํ ์ธ๊ธ์ก์ 0์ด์ด์ผ ํ๊ธฐ ๋๋ฌธ
}
}
ํ ์คํธ ์ฝ๋ ๋ง๋ค ๋ ctrl+alt+t
๋ชจ๋ฅด๊ฒ ์ผ๋ฉด ๋ ๋ค alt+enter
- ์๋ก์ด ํ ์ธ ์ ์ฑ ์ ์ฉ๊ณผ ๋ฌธ์ ์
<๋ฌธ์ ์ >
1. DIP ์๋ฐ
์ถ์ํ & ๊ตฌ์ฒดํ ๋ชจ๋ ์์กด์ค
์ฐ๋ฆฌ๋ ์ถ์ํ๋ง ์์กดํ๊ณ ์๋ ๊ฒ์ ํฌ๋งํจ
2. OCP ์๋ฐ
ํ ์ธ ์ ์ฑ ์ ๋ณ๊ฒฝํ๋ ค๋ฉด, ํด๋ผ์ด์ธํธ์ธ OrderServiceImpl์ ๋ณ๊ฒฝํด์ผ ํ๋ค.
//OrderServiceImpl.java
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository = new MemoryMemberRepository();//1
//private final DiscountPolicy discountPolicy = new FicDiscountPolicy();->
private final DiscountPolicy discountPolicy = new RateDiscountPolicy(); //2
/*์๋ต*/
}
<ํด๊ฒฐ>
DiscountPolicy๋ง ์ผ๋จ ํด๋ณด๊ธฐ
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository = new MemoryMemberRepository();
private DiscountPolicy discountPolicy;
//ํ์ง๋ง ์ด๊ฒ๋ NULL์ด๊ธฐ ๋๋ฌธ์ ์ค๋ฅ๊ฐ ๋ ๊ฒ
/*์๋ต*/
}
์ญ์ ์ค๋ฅ๊ฐ ๋๋ discountPolicy์ fix๋ rate๋ ๊ณจ๋ผ์ ๋ฃ์ด์ค ๋๊ตฐ๊ฐ๊ฐ ํ์ํ๋ค.
- ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ
"๊ณต์ฐ ๊ธฐํ์๋ฅผ ๋ง๋ค๊ณ , ๊ณต์ฐ ๊ธฐํ์์ ๋ฐฐ์ฐ์ ์ฑ ์์ ํ์คํ ๋ถ๋ฆฌํ์"
//AppConfig.java
public class AppConfig {
public MemberService memberService(){
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService(){
return new OrderServiceImpl(new MemoryMemberRepository(), new FicDiscountPolicy());
}
}
์ ๋ง... AppConfig ๋ง๋ค ๋ ์๋ฆ๋ผ์ณค์... ์ด๊ฒ ์ด๋ ๊ฒ ๋ ์ ์๋ค๋....
๊ฐ์ฌ๋ ์ด๊ฑฐ ๋ง ์ค๋ช ํ๋๋ฐ ์ ๊ฐ๊ณ ๋ง
์ ๋ง ์ด๋ฐ๊ฑฐ ๋ง๋ค์ด๋์ ์ฌ๋๋ค ๋ค ๋๋ฐ์ ์ฒ์ฌ ๋ง์ฌ์ ในใ
//OrderServiceImpl.java
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;
}
/*์๋ต*/
}
//MemberServiceImpl.java
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
/*์๋ต*/
}
์์ฑ์๋ก ๊ฝ์ ๋ฃ์ ์ ์๊ฒ ๊ณ ์นฉ๋๋ค..!!
private final๋ก ์ธํฐํ์ด์ค ์ ์ธํ๊ณ , ๊ตฌ์ฒดํ ํด๋์ค ๋ฐ์์ ์์ฑํ๋๋ก ์์ฑ์ ๋ง๋ค๊ธฐ
AppConfig๊ฐ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ , ์ฐ๊ฒฐ
Impl์ ์คํ์๋ง ์ง์คํ๋ค.
=> ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ
//MemberApp.java
public class MemberApp {
public static void main(String[] args){
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
/*์๋ต*/
}
}
//OrderApp.java
public class OrderApp {
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
OrderService orderService = appConfig.orderService();
/*์๋ต*/
}
}
๋ก์ง์ผ๋ก ํ ์คํธํ๋ ์ฝ๋์๋ AppConfig์์ ๋ฐ์์จ ๊ฑธ ๋ฃ์ด์ ํ ์คํธ ํด์ค๋๋ค.
ctrl + E ( + ์ํฐ) ์ต๊ทผ ํ์ผ
//MemberServiceTest.java
public class MemberServiceTest {
MemberService memberService;
@BeforeEach
public void beforeEach(){
AppConfig appConfig = new AppConfig();
memberService = appConfig.memberService();
}
/*์๋ต*/
}
//OrderServiceTest.java
public class OrderServiceTest {
MemberService memberService;
OrderService orderService;
@BeforeEach
public void beforeEach() {
AppConfig appConfig = new AppConfig();
memberService = appConfig.memberService();
orderService = appConfig.orderService();
}
/*์๋ต*/
}
jUnit์ผ๋ก ํ ์คํธ ํ๋ ์ฝ๋์๋ ํด์ค๋๋ค. BeforeEach๋ ํ ์คํธ ์คํํ๊ธฐ ์ ์ ์คํํ๋ ์ฝ๋
- AppConfig ๋ฆฌํฉํฐ๋ง
ํ์ฌ AppConfig๋ฅผ ๋ณด๋ฉด ์ค๋ณต์ด ์๊ณ , ์ญํ ์ ๋ฐ๋ฅธ ๊ตฌํ์ด ์ ์๋ณด์ธ๋ค.
//AppConfig.java
public class AppConfig {
//์ญํ ์ด ํ๋์ ๋ค์ด์จ๋ค.
public MemberService memberService(){
return new MemberServiceImpl(memberRepository());
}
public OrderService orderService(){
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
//์ค๋ณต์ ๊ฑฐ. ์์ ํ ๋ ์ฌ๊ธฐ๋ง ์์ ํ๋ฉด ๋จ
public MemoryMemberRepository memberRepository() {
return new MemoryMemberRepository();
}
public DiscountPolicy discountPolicy(){
return new FicDiscountPolicy();
}
}
์ค๋ณต๋๋๊ฑฐ์ ๋๊ณ ctrl+alt+M : ์ค๋ณต ์ ๊ฑฐ
์ ์ ๋ง ์ด ๋ถ๋ถ ๋๋ฌด ๊ฐ๋์ ์ด์ผ... ์ธ์์ ์ด๋ ๊ฒ ์ฝ๋๊ฐ ์์๊ฒ ๋๋ค๋...
๊ฐ์ฌ๋ ์ ๋ง ์ฒ์ฌ์ผ....
๊ทผ๋ฐ ๋ด๊ฐ ์ด๊ฑธ ๋จธ๋ฆฟ์์ ๋ฃ๊ณ ํผ์ ๋ง๋ค์ด ๋ผ ์ ์์๊น?? ์ด๋ฐ ์๊ฐ ๋ชปํ ๊ฒ๊ฐ์๋ฐ ใ ใ ใ
- ์๋ก์ด ๊ตฌ์กฐ์ ํ ์ธ ์ ์ฑ ์ ์ฉ
//AppConfig.java
public class AppConfig {
/*์๋ต*/
public DiscountPolicy discountPolicy(){
//return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
}
ํ ์ค๋ง ์์ ํ๋ฉด ํ ์ธ ์ ์ฑ ๋ฐ๋
๊ตฌ์ฑ ์์ญ๋ง ์๋๋ฉด ๋๊ณ ์ฌ์ฉ์์ญ์ ์ ํ ์ ๋ ํ์ ์๋ค.
์ด์ DIP์ OCP๋ฅผ ์งํฌ ์ ์๋ค!!
๊ตฌ์ฑ ์์ญ๊ณผ ์ฌ์ฉ ์์ญ์ผ๋ก ๋ถ๋ฆฌ๊ฐ ๋์๋ค.
๊ตฌ์ฑ ์์ญ์ธ AppConfig๋ง ์์ ํ๋ฉด ์ ์ฑ ์ ๋ณ๊ฒฝํ ์ ์์
- ์ข์ ๊ฐ์ฒด์งํฅ ์ค๊ณ์ 5๊ฐ์ง ์์น์ ์ ์ฉ
SRP - ํ ํด๋์ค๋ ํ๋์ ์ฑ ์๋ง ๊ฐ์ ธ์ผ ํ๋ค.
ํด๋ผ์ด์ธํธ : ๊ตฌํ ๊ฐ์ฒด ์์ฑ/์ฐ๊ฒฐ, ์คํ
-๊ด์ฌ์ฌ ๋ถ๋ฆฌ->
AppConfig : ๊ตฌํ ๊ฐ์ฒด ์์ฑ/์ฐ๊ฒฐ
ํด๋ผ์ด์ธํธ : ๊ฐ์ฒด ์คํ
DIP - ์ถ์ํ์ ์์กดํด์ผ ํ์ง, ๊ตฌ์ฒดํ์ ์์กดํ๋ฉด ์๋๋ค.
์ถ์ํ ์ธํฐํ์ด์ค์ ๊ตฌ์ฒดํ ๊ตฌํ ํด๋์ค๋ฅผ ์์ฑํ๋ ๋ถ๋ถ์ด ์์์ผ๋ฏ๋ก,
๊ฒ๋ณด๊ธฐ์ ์ถ์ํ ์ธํฐํ์ด์ค์ ์์กดํ๋ ๊ฒ ๊ฐ์ง๋ง, ๋ฟ๋ง ์๋๋ผ ๊ตฌํ ํด๋์ค์๋ ์์กดํ๋ ๊ฒ ๋์ด๋ฒ๋ ธ๋ค.
-๊ตฌํํด๋์ค ํํธ ์ ๊ฑฐ->
ํด๋ผ์ด์ธํธ ์ฝ๋๋ ์ธํฐํ์ด์ค๋ง์ผ๋ก๋ ์๋ฌด๊ฒ๋ ์คํํ ์ ์๋ค.
-์์กด๊ด๊ณ ์ฃผ์ ->
AppConfig๊ฐ ๋์ ๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ์์ฑํด์ ์์กด๊ด๊ณ ์ฃผ์ ํจ
OCP - ํ์ฅ์๋ ์ด๋ ค์์ผ๋ ๋ณ๊ฒฝ์๋ ๋ซํ ์์ด์ผ ํ๋ค.
์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ์ฉ ์์ญ๊ณผ ๊ตฌ์ฑ ์์ญ์ผ๋ก ๋๋
๊ตฌ์ฑ ์์ญ์ AppConfig๋ง ๊ณ ์น๋ฉด ํ์ฅ์ด ๊ฐ๋ฅํด์ก๋ค.
-> ์ฌ์ฉ ์์ญ์ ๋ณ๊ฒฝ์๋ ๋ซํ์๋ค.
- IoC, DI, ๊ทธ๋ฆฌ๊ณ ์ปจํ ์ด๋
์ ์ด์ ์ญ์ (IoC : Inversion of Control)
์ง์ ๊ด๋ฆฌํ๋ ๊ฒ์ด ์๋๋ผ ์ธ๋ถ์์ ๊ด๋ฆฌํ๋ ๊ฒ
ex) ๊ตฌํ ๊ฐ์ฒด๊ฐ ํ๋ก๊ทธ๋จ์ ์ ์ด ํ๋ฆ์ ๊ฐ์ง๋ ๊ฒ์ด ์์ฐ์ค๋ฌ์ด ํ๋ฆ์ธ๋ฐ ์ด์ AppConfig๊ฐ ์ ์ด ํ๋ฆ์ ๊ฐ์ ธ๊ฐ๋ค.
ํ๋ ์์ํฌ vs๋ผ์ด๋ธ๋ฌ๋ฆฌ
ํ๋ ์์ํฌ๊ฐ ๋ด๊ฐ ์์ฑํ ์ฝ๋๋ฅผ ์ ์ดํ๊ณ , ๋์ ์คํํ๋ฉด ํ๋ ์์ํฌ
๋ด๊ฐ ์์ฑํ ์ฝ๋๊ฐ ์ง์ ์ ์ด์ ํ๋ฆ์ ๋ด๋นํ๋ฉด ๋ผ์ด๋ธ๋ฌ๋ฆฌ
์์กด๊ด๊ณ ์ฃผ์ (DI : Dependency Injection)
∨ ์ ์ ์ธ ํด๋์ค ์์กด ๊ด๊ณ
import๋ง ๋ณด๊ณ ๋ ์์กด๊ด๊ณ๋ฅผ ํ๋จํ ์ ์๋ค.
ํ์ง๋ง ์ด๋ค ๊ตฌํ ๊ฐ์ฒด๊ฐ ์ฌ์ฉ๋ ์ง๋ ๋ชจ๋ฅธ๋ค.
ex ) OrderServiceImpl๊ณผ MemberRepository, DiscountPolicy์ ๊ด๊ณ
∨ ๋์ ์ธ ๊ฐ์ฒด ์ธ์คํด์ค ์์กด ๊ด๊ณ
์คํ ์์ ์ ๊ฒฐ์ ๋๋ ๋์ ์ธ ๊ฐ์ฒด
๋ฐํ์ ๋ด์์ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ํด๋ผ์ด์ธํธ๋ก ์ ๋ฌ
์ ์ ์ธ ํด๋์ค ์์กด๊ด๊ณ๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ ๋์ ์ธ ๊ฐ์ฒด ์ธ์คํด์ค ์์กด ๊ด๊ณ๋ฅผ ์ฝ๊ฒ ๋ณ๊ฒฝํ ์ ์๋ค.
ex) DiscountPolicy์ FixDiscountPolicy, RateDiscountPolicy์ ๊ด๊ณ
IoC์ปจํ ์ด๋, DI์ปจํ ์ด๋
AppConfig์ฒ๋ผ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ด๋ฆฌํ๋ฉด์ ์์กด๊ด๊ณ๋ฅผ ์ฐ๊ฒฐํด ์ฃผ๋ ๊ฒ์
IoC์ปจํ ์ด๋ ๋๋ DI์ปจํ ์ด๋(ํน์ฑ์ ๋ง๋ ์์ด๋ฆ)๋ผ๊ณ ํ๋ค.
์คํ๋ง์ด DI์ปจํ ์ด๋ ์ญํ ์ ํ๋ค. ์คํ๋ง ๋ง๊ณ ๋ ๋ง๋ค.
- ์คํ๋ง์ผ๋ก ์ ํํ๊ธฐ
์์ํ ์๋ฐ ์ฝ๋๋ก DI๋ฅผ ์ ์ฉํ์ง๋ง, ์ด์ ์คํ๋ง์ ์ ์ฉํด๋ณธ๋ค.
//AppConfig.java
@Configuration // ์ค์ ์ ๋ณด์ ์ ์
public class AppConfig {
//์ญํ ์ด ํ๋์ ๋ค์ด์จ๋ค.
@Bean //Spring Container์ ๋ฑ๋ก
public MemberService memberService(){
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService(){
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
//์ค๋ณต์ ๊ฑฐ. ์์ ํ ๋ ์ฌ๊ธฐ๋ง ์์ ํ๋ฉด ๋จ
@Bean
public MemoryMemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public DiscountPolicy discountPolicy(){
return new FicDiscountPolicy();
}
}
๊ธฐ๋ณธ์ ์ผ๋ก ๋ฉ์๋ ์ด๋ฆ์ผ๋ก Bean ์ด๋ฆ์ด ๋ฑ๋ก๋๋ค.
//MemberApp.java
public class MemberApp {
public static void main(String[] args){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
/*์๋ต*/
}
}
//OrderApp.java
public class OrderApp {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
/*์๋ต*/
}
}
์ด๋ ๊ฒ ์์ ์ ํ๊ณ ํ ์คํธ ์ฝ๋๋ฅผ ์คํ์์ผ ๋ณด๋
์๋ ๊ฒ ๋ญ๊ฐ appConfig์ ๊ทธ ์๋ ๋ฉ์๋๋ค์ ์ด๋ฆ์ด ๋์ค๋ฉฐ ์ ์คํ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์คํ๋ง ์ปจํ ์ด๋๋ @Configuration์ด ๋ถ์ ํด๋์ค๋ฅผ ๊ตฌ์ฑ ์ ๋ณด๋ก ์ฌ์ฉํจ.
@Bean์ด ์ ํ ๋ฉ์๋๋ฅผ ๋ชจ๋ ํธ์ถํด์ ๋ฐํ๋ ๊ฐ์ฒด๋ฅผ ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋กํจ.
์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋ก๋ ๊ฐ์ฒด : ์คํ๋ง ๋น
๋ณดํต ๋ฉ์๋ ๋ช ์ด ์คํ๋ง ๋น์ ์ด๋ฆ์ด ๋๋ค(name = ์ด์ฉ๊ตฌ ํด์ ๋ฐ๊ฟ ์๋ ์๋๋ฐ ๊ตณ์ด..?)
์ด์ ์ ์๋ฐ ์ฝ๋๋ก ์ผ์ผ์ด ํ๋ค๋ฉด,
์ด์ ํ์ํ ๋๋ง๋ค ์ฝ๊ฒ applicationContext.getBean() ๋ฉ์๋๋ฅผ ์ด์ฉํด ์คํ๋ง ์ปจํ ์ด๋์์ ๊ฐ์ฒด๋ฅผ ์ฐพ์ ์ ์๋ค.
ํ์ง๋ง ์์ง ์ด๊ฒ ์ ์ข์์ง ๋ชจ๋ฅด๊ฒ ๋ค!! ๊ทผ๋ฐ ๊ฐ์ฌ๋์ด ๋ค์ ๊ฐ์ ๋ ์๋ ค์ฃผ์ ๋ค๊ณ ํ์ จ๋ค!!