객체 지향 원리 적용
인프런 스프링 핵심 원리 - 기본편 수강 중
객체 지향 문제점
- 역할과 구현 분리 ➡️ OK
- 다형성 활용, 인터페이스 구현 객체 분리 ➡️ OK
- OCP, DIP 객체지향 설계 원칙 준수 ➡️ NO
- DIP: 추상 클래스(인터페이스) 뿐만 아니라 구현 클래스에도 의존
- OCP: FixDiscountPolicy에서 RateDiscountPolicy로 변경되면서 소스코드가 변경됨
DIP 위반
OCP 위반
인터페이스에만 의존하도록 설계 변경
객체지향 문제점 해결
의존성 문제부터 해결
//private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
private DiscountPolicy discountPolicy;
DIP는 지켰지만 구현체가 없기 떄문에 NullPointerException
발생
관심사 분리
구현 객체를 생성하고 연결을 책임지는 별도 설정 클래스 생성
MemberServiceImpl - 생성자 주입
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
- MemberServiceImple 코드 안에 MemoryMemberRepository 관련 코드는 없음
➡️ MemoryMemberRepository에 의존하지 않고 인터페이스에만 의존 - 어떤 레포지토리를 사용할 것인지는 AppConfig가 결정
- AppConfig가 생성과 연결을 담당
- 인터페이스에만 의존
OrderServiceImpl - 생성자 주입
private final MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
- OrderServiceImple 코드 안에 MemoryMemberRepository 관련 코드와 FixDiscountPolicy 관련 코드는 없음
➡️ MemoryMemberRepository와 FixDiscountPolicy에 의존하지 않고 인터페이스에만 의존 - 어떤 레포지토리를 사용할 것인지, 어떤 할인 정책을 사용할 것인지는 AppConfig가 결정
AppConfig
public class AppConfig {
public MemberService MemberServiceImpl() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
}
}
- AppConfig에서 실제 동작에 필요한 구현 객체 생성
- MemberServiceImpl
- MemoryMemberRepository
- OrderServiceImpl
- FixDiscountPolicy
- 외부(AppConfig)에서
MemberServiceImpl
과OrderServiceImpl
에 의존관계를 주입하기 때문에 이를 DI(Dependency Injection), 의존관계 주입, 의존성 주입이라 한다.
MemberApp
//MemberService memberService = new MemberServiceImpl();
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
AppConifg 적용
OrderApp
AppConfig appConfig = new AppConfig();
//MemberService memberService = new MemberServiceImpl();
MemberService memberService = appConfig.memberService();
//OrderService orderService = new OrderServiceImpl();
OrderService orderService = appConfig.orderService();
AppConfig 적용
테스트 파일 수정
MemerServiceTest
//MemberService memberService = new MemberServiceImpl();
MemberService memberService;
@BeforeEach
public void beforeEach(){
AppConfig appConfig = new AppConfig();
memberService = appConfig.memberService();
}
- \@BeforEach 어노테이션은 테스트 실행하기 전에 해당 메서드를 실행하도록 한다
- AppConfig 적용
OrderServiceTest
//MemberService memberService = new MemberServiceImpl();
//OrderService orderService = new OrderServiceImpl();
MemberService memberService;
OrderService orderService;
@BeforeEach
public void beforeEach(){
AppConfig appConfig = new AppConfig();
memberService = appConfig.memberService();
orderService = appConfig.orderService();
}
AppConfig 적용
AppConfig 리팩터링
역할에 따른 구현이 잘 안 보임
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
public DiscountPolicy discountPolicy(){
return new FixDiscountPolicy();
}
}
- 메서드를 구현해서 중복되는
new MemoryMemberRepository()
제거 - 레포지토리나 할인 정책이 바뀌면 한 부분만 바꾸면 됨
- 역할 구현 부분이 한 눈에 보임
정률 할인 정책으로 변경
- AppConfig 구현으로 애플리케이션이 사용 영역과 구성 영역으로 분리
- 변경되어도 사용 영역을 건드릴 필요가 없음
public DiscountPolicy discountPolicy() {
//return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
AppConfig에서 FixDiscountPolicy
를 RateDiscountPolicy
로 변경만 하면 끝
[참조] 인프런 스프링 핵심 원리 - 기본편 - 링크
끝!