section2에서 작성했던 순수 java코드의 여러 문제를 발견했었다. 리팩토링하면서
SOLID 원칙 5가지를 어떻게 지키는지 포커스를 두며 공부할 것.
내용 및 다이어그램 및 코드 부분 인용의 모든 출처는 김영한님의 인프런 스프링 강의입니다.
고정 할인 -> 비율 할인으로 변경하려고 하면?
public class OrderServiceImpl implements OrderService {
// private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
}
새로 개발한 정률 할인 정책을 적용하려고 하니 클라이언트 코드인 주문 서비스 구현체도 함께 변경해야함 -> OCP 위반
주문 서비스 클라이언트가 인터페이스인 DiscountPolicy 뿐만 아니라, 구체 클래스인
FixDiscountPolicy 도 함께 의존 -> DIP 위반
1. 인터페이스에만 의존하도록 변경
public class OrderServiceImpl implements OrderService {
//private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
private final DiscountPolicy discountPolicy;
}
이렇게만 하면 final은 무조건 초기화를 시켜줘야 되기 때문에 그냥 실행하면 무시무시한 NPE 발생.
따라서 누군가 클라이언트인 OrderServiceImpl 에 DiscountPolicy 의 구현 객체를
대신 생성하고 주입해주어야 한다.
2. AppConfig 등장
애플리케이션의 전체 동작 방식을 구성(config)하기 위해, 구현 객체를 생성하고, 연결하는 책임을 가지는 별도의 설정 클래스를 만들 것.
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(
new MemoryMemberRepository(),
new FixDiscountPolicy());
}
}
/*참고 - 리팩토링 전 코드다*/
/*클라이언트 코드에는 생성자를 추가한다.*/
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
기능기능기능
}
3. AppConfig 리팩토링
AppConfig.java 의 코드를 보면 중복이 있고, 역할에 따른 구현이 한눈에 보이지 않음.
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(
memberRepository(),
discountPolicy());
}
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
public DiscountPolicy discountPolicy() {
return new FixDiscountPolicy();
}
}
리팩토링 후 :
클래스 다이어그램
DIP : ( 인터페이스 변수 선언 만 하고 끝나기 때문에 추상에만 의존하게 됨 )
OCP : ( AppConfig는 당연히 바꾸긴 하는데, 클라이언트 코드는 안바꾸잖아 )
결국 둘다 지키게 됨!!!!!
전체 흐름 정리 ,좋은 객체 지향 설계의 5가지 원칙의 적용 부분 (앞내용 정리긴 함)
이부분은 매우 중요하니 블로그를 보는 것 보다는 pdf 및 강의로 복습 하는것이 좋다.ㅎㅎ
OrderServiceImpl 보필요한 인터페이스들을 호출하지만 어떤 구현 객체들이 실행될지 모른다.
이 제어권들이 모두 AppConfig로 넘어간 상황. 심지어 OrderServiceImpl 도 AppConfig가 생성함.
프레임워크가 내가 작성한 코드를 제어하고, 대신 실행하면 그것은 프레임워크가 맞다. (JUnit)
반면에 내가 작성한 코드가 직접 제어의 흐름을 담당한다면 그것은 프레임워크가 아니라 라이브러리다.
Junit 같은 경우를 보면 , JUnit으로 테스트 작성시 @Test 에 개발자는 로직만 작성하고, 실행 및 제어권은 JUnit이 가져감.
자신만의 라이프 사이클로다가 ( , @BeforeEach , @AfterEach 애노테이션 등을 활용)