

김영한 Spring 기본편 강의 3 정리카테고리 없음2024. 4. 12. 17:14
Table of Contents
📖 새로운 할인 정책의 추가
- RateDiscountPolicy라는 새로운 할인 정책 구현체 요구됨
📖 RateDiscountPolicy
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;
}
}
}
- VIP인 경우 할인율 적용
- discount에 대한 테스트를 만들 때 ctril + shift + t 키를 통해 빠르게 만들 수 있다.
📖 Discount 시스템의 문제점
- OrderServiceImpl이 FixDiscountPolicy , RateDiscountPolicy와 같은 구현 클래스에 의존하고 있음, 이 때문에 할인 정책 변경 시 OrderServiceImpl 코드도 변경해야함
- DIP 위반
📖 기존 코드 변경
public class OrderServiceImpl implements OrderService {
//private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
private DiscountPolicy discountPolicy;
}
- 인터페이스에만 의존하도록 변경한 형태
- 이 경우 구현 DiscountPolicy의 구현 객체를 생성할 무언가가 필요
- 관심사의 분리 : 기존의 코드는 배우(구현체)가 직접 다른 배우를 섭외하고 역할을 지정한 느낌, 별도의 공연 기획자가 필요
📖 AppConfig
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
}
}
- 동작에 필요한 구현 객체를 생성하고 연결하는 일을 하는 별도의 클래스
- new MemberServiceImpl(new MemoryMemberRepository());와 같이 생성자에 객체를 인자로 전달하며 MemberServiceImpl은 MemoryMemberRepository에게 의존하게 됨, 이 때 이 의존성은 AppConfig이 주입(연결)
- 의존관계에 대한 부분은 AppConfig에게 전담
- 할인정책을 바꾸기를 원할 경우 new FixDiscountPolicy() 부분만 수정하면 됨
📖 기존 MemberServiceImpl 변경(생성자 주입)
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
} // 생성자 주입
- MemberServiceImpl은 구체적 메모리 구현체의 형테, 예를 들어 MemoryMemberRepository인지는 알필요가 없어졌다.
- 같은 방식으로 OrderServiceImpl도 생성자를 주입한다.
📖 클래스 다이어그램
- 객체의 생성 및 연결은 AppConfig이 함
- 의존문제(DIP) 해결 : MemberServiceImpl은 MeberRepository(역할)에만 의존
📖 회원 객체 인스턴스 다이어그램
- MemberServiceImpl의 의존 관계를 외부인 appConfig에서 주입, DI(Dependency injection)
📖 Appconfig 중복 제거 리팩터링
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(
new MemoryMemberRepository(),
new FixDiscountPolicy());
}
}
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();
}
}
- new MemoryMemberRepository() 중복 제거
- 역할 및 구현 명확히 분리
📖 Appconfig 의 결과
- 이제 할인 정책 등을 변경해도 사용 영역은 영향을 받지 않게 되었다.
📖 적용된 SRP 단일 책임 원칙
한 클래스는 하나의 책임만 가져야한다
- 구현 객체를 생성하고 연결하는 책임은 AppConfig가 담당
- 클라이언트 객체는 실행하는 책임만 담당
📖 적용된 DIP 의존관계 역전 원칙
추상화에 의존해야한다. 구체화에 의존하면 안된다
- 클라이언트 코드가 DiscountPolicy 추상화 인터페이스에만 의존하도록 변경
- AppConfig가 객체 인스턴스를 클라이언트 대신 생성하고 의존 주입
📖 적용된 OCP 원칙
소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다
- AppConfig가 의존관계를 FixDiscountPolicy RateDiscountPolicy 로 변경해도 사용 영역인 클라이언트 코드는 변경 안 해도 됨
📖 IoC(제어의 역전)
- 기존 프로그램 : 구현 객체 스스로 객체 생성,연결,실행
- AppConfig 등장 : 구현 객체는 자신의 로직을 실행하는 역할만 담당
- 프로그램 제어의 흐름을 외부에서 관리
📖 프레임워크와 라이브러리
- JUnit : 프레임워크가 코드 직접 제어 및 실행(프레임워크)
- test 프로그램 : 내부 직접 작성 코드가 제어 흐름 담당(라이브러리)
📖 DI(의존관계 주입)
- 정적 의존관계 : import 한 코드들
- 동적 의존관계 : app 실행 시점에 생성된 객체 인스턴스 참조가 연결됨
- 의존관계 주입 : 실행시점에 외부에서 실제 구현 객체 생성해 클라이언트에 전달해 클라이언트와 서버가 의존관계로 연결되는 것
📖 IoC 컨테이너, DI 컨테이너
- AppConfig 처럼 객체 생성,관리,연결하는 것을 칭함.
📖 Spring Container
- ApplicationContext
- 설정을 구상한다는 뜻의 @Configuration을 붙임, 스프링 컨테이너는 이 @Configuration이 붙은 AppConfig를 설정 정보로 사용함
- 각 메소드의 앞에는 @Bean, 스프링 컨테이너의 스프링 빈으로 등록됨, 스프링 컨테이너에 등록된 객체
- 기존 AppConfig 역할 대체하고 필요한 스프링 빈 주입
- 스프링 빈은 applicationContext.getBean()을 통해 찾을 수 있음

@바이솔 :: Byesol의 기록