김영한님의 스프링 핵심 원리 강의 학습 내용입니다.
스프링 핵심 원리 이해
- HashMap은 동시성 이슈 발생 가능성이 있다. 이 경우 ConcurrentHashMap을 사용해야 한다.
의존관계의 문제점
public class OrderServiceImpl implements OrderService{
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
}
- 인터페이스와 구현클래스 모두에 의존하고 있다. : DIP 위반
- RateDiscountPolicy로 바꾸는 순간 OrderServiceImpl 소스 코드의 변경이 발생한다. : OCP 위반
해결방안
public class OrderServiceImpl implements OrderService{
private DiscountPolicy discountPolicy;
}
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;
}
}
public class AppConfig {
public OrderService orderService(){
return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
}
}
- 인터페이스에만 의존하고 있다.
- OrderServiceImpl은 구체 클래스를 몰라도 된다.
- AppConfig가 애플리케이션 실제 동작에 필요한 구현 객체를 생성한다.
- AppConfig는 생성한 객체 인스턴스 참조를 생성자를 통해 주입해준다.
- DI, 의존관계 주입
MemberApp, OrderApp
public class MemberApp {
public static void main(String[] args) {
MemberService memberService = new MemberServiceImpl();
}
public class MemberApp {
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
}
Test
public class MemberServiceTest {
MemberService memberService = new MemberServiceImpl();
}
public class MemberServiceTest {
MemberService memberService;
@BeforeEach
public void beforeEach(){
AppConfig appConfig = new AppConfig();
memberService = appConfig.memberService();
}
}
AppConfig 리팩터링
public class AppConfig {
public MemberService memberService(){
return new MemberServiceImpl(memberRepository());
}
private MemoryMemberRepository memberRepository() {
return new MemoryMemberRepository();
}
public OrderService orderService(){
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
public DiscountPolicy discountPolicy(){
return new FixDiscountPolicy();
}
}
- Extract Method : Ctrl + Alt +M
- 역할과 구현을 분리 : SRP
- 역할과 구현 클래스를 볼 수 있다.
public DiscountPolicy discountPolicy(){
return new RateDiscountPolicy();
}
- FixDiscountPolicy에서 RateDiscountPolicy로 바꿀 때 AppConfig만 변경하면 된다.
- 사용영역의 코드는 변경할 필요가 없다. : OCP
IoC - 제어의 역전
- 프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것
의존관계
정적인 클래스 의존관계
- 클래스의 import 코드만 보고 의존관계를 쉽게 판단
- 애플리케이션을 실행하지 않아도 분석가능
- Diagrams - Show Diagram - Show Dependencies
동적인 객체 인스턴스 의존관계
- 애플리케이션 런타임에 외부에서 실제 구현 객체를 생성하고 클라이언트에 전달해 클라이언트와 서버의 실제 의존관계가 연결된다 - DI(의존관계 주입)
DI
- 클라이언트 코드를 변경하지 않고 클라이언트가 호출하는 대상의 타입 인스턴스를 변경할 수 있다.
- 정적인 클래스 의존관계를 변경하지 않고 동적인 객체 인스턴스 의존관계를 변경할 수 있다.
IoC 컨테이너, DI 컨테이너
- 객체를 생성하고 관리하며 의존관계를 연결해 주는 것(EX) AppConfig)
깔끔한 정리 너무 좋군요 ^^