티스토리 뷰
DI(Dependency Injection)
DI란 스프링이 제공하는 의존 관계 주입 기능으로, 객체를 직접 생성하는 것이 아닌 외부 APP에서 생성한 후 객체를 주입 시켜주는 방식이다. DI를 통해 모듈 간의 결합도(Coupling)이 낮아지고 유연성이 높아진다.
좋은 소프트웨어를 설계하기 위해서는 응집도(Cohesion)는 높아야 하고 결합도(Coupling)은 낮아야 한다.
방법 1은 A 객체가 B와 C객체를 직접 생성자를 통해서 생성하는 방법이고
방법 2는 외부에서 생성된 객체를 setter()나 생성자를 통해 사용하는 방법이다
주문 시스템의 클래스 다이어그램을 살펴보면 문제점을 찾을 수 있다.
할인 정책을 고정 할인 정책에서 비율 할인 정책으로 변경하는 경우 클라이언트 코드인 OrderServiceImpl 클래스에서 할인 정책을 변경해야 한다.
-> 추상(인터페이스) 뿐만 아니라 구체(구현) 클래스에도 의존하고 있다.
즉 방법 1의 방식으로 구현되어 있는 것이다.
반드시 추상에만 의존하도록 변경해야 된다! (인터페이스에만 의존)
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository = new MemoryMemberRepository();
/**
* 고정 할인 정책 -> 비율 할인 정책으로 할인 정책을 변경하는 경우
* 클라이언트 코드인 OrderServiceImpl은 DiscountPolicy 인터페이스 뿐만 아니라 구현 클래스도 함께 의존
* 그래서 구현 클래스(고정, 비율)를 변경할 때, OrderServiceImpl도 같이 변경해야 된다
* DIP 위반이므로 추상(Interface)에만 의존하도록 변경해야된다
*/
private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
}
OrderServiceImpl 클래스에서 private final DiscountPolicy discountPolicy = new FixDiscountPolicy(); 를 통해 의존관계를 주입하고 있다. 만약 비율 할인 정책으로 바꾸게 된다면 OrderServiceImpl 클래스 에서 로직을 수정해야 한다.
-> DI 위반
public class AppConfig {
/**
* 애플리케이션에 관한 모든 환경 구성은 AppConfig에서 한다
* AppConfig 에서 앱과 관련된 구현 객체를 생성자 주입의 방식으로 설정한다
*
* @return
*/
public MemberService memberService(){
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService(){
return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
}
}
따라서 애플리케이션에 관한 모든 환경 구성을 하는 AppConfig 클래스를 정의한다.
AppConfig 클래스에서 앱과 관련한 구현 객체를 생성자 주입 방식으로 설정하고
public class OrderServiceImpl implements OrderService{
/**
* 그래서 생성자 주입의 방식으로 정의한다
* 따라서 MemberRepository, DiscountPolicy 와 같은 인터페이스에만 의존한다
*/
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
OrderServiceImpl 코드를 다음과 같이 생성자를 이용하여 DI를 주입하는 방식을 사용한다.
public class MemberApp {
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
Member member = new Member(1L, "memberA", Grade.VIP);
memberService.join(member);
Member findMember = memberService.findMember(1L);
System.out.println("findMember = " + findMember.getName());
System.out.println("member = " + member.getName());
}
}
애플리케이션 내부에서는 사용할 때 AppConfig 객체를 만들어 할당해주면 된다.
'Spring' 카테고리의 다른 글
[Spring] Spring Singleton(싱글톤) (0) | 2022.01.17 |
---|---|
[Spring] Spring Container(스프링 컨테이너) (0) | 2022.01.14 |
[Spring] 좋은 객체 지향이란? (0) | 2021.08.05 |
[Spring] 스프링이란? (스프링 프레임워크 VS 스프링 부트) (0) | 2021.08.05 |
[Spring] 스프링 라이브러리 살펴보기 (0) | 2021.07.20 |
- Total
- Today
- Yesterday
- 우테코 회고
- 네트워크
- CI/CD
- 스프링MVC
- dm-zoned 코드분석
- 피움
- 피움 6주차 회고
- 팀프로젝트
- 프로젝트
- 우테코
- 스프링 부트
- 백준
- Spring
- 5주차 회고
- 8주차 회고
- 알림기능개선기
- 환경 별 로깅 전략 분리
- dm-zoned
- ZNS SSD
- 스프링 Logback
- 알림개선기
- 파이썬
- 3차 데모데이
- 회고
- ZNS
- 2차 데모데이
- 런칭 페스티벌
- jpa
- java
- 스프링 프레임워크
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |